From 7345f42201a1a5bc02b8b38d55cf3e208fd2ad0a Mon Sep 17 00:00:00 2001 From: Nathaniel Cosford Date: Wed, 4 Jun 2025 16:13:32 +0930 Subject: [PATCH] Upload from upload_mods.ps1 --- .gitignore | 80 + Config/Localization.txt | 31 + Config/buffs.xml | 30 + CustomPlayerActionManager.dll | Bin 0 -> 18432 bytes CustomPlayerActionManager.pdb | Bin 0 -> 11832 bytes DOTween.Modules.dll | Bin 0 -> 43520 bytes DOTween.Modules.pdb | Bin 0 -> 26392 bytes DOTween.XML | 3077 +++++++++++ DOTween.dll | Bin 0 -> 175104 bytes DOTween.dll.mdb | Bin 0 -> 67637 bytes ...cherAnimationRiggingCompatibilityPatch.dll | Bin 0 -> 16384 bytes ...cherAnimationRiggingCompatibilityPatch.pdb | Bin 0 -> 9528 bytes .../SMXMultiActionCompatibilityPatch.dll | Bin 0 -> 10240 bytes .../SMXMultiActionCompatibilityPatch.pdb | Bin 0 -> 8384 bytes GearsAPI.dll | Bin 0 -> 10752 bytes Harmony/AnimationRiggingPatches.cs | 1731 +++++++ Harmony/BackgroundInventoryUpdatePatch.cs | 51 + Harmony/DamagePatches.cs | 174 + Harmony/DisplayMetaAsBuffPatch.cs | 21 + Harmony/FPVLegPatches.cs | 34 + Harmony/HideMarkerOnAimPatch.cs | 45 + Harmony/Init.cs | 96 + Harmony/InvariableRPMPatches.cs | 73 + Harmony/ItemActionModulePatch.cs | 41 + Harmony/ModularPatches.cs | 343 ++ Harmony/MultiActionPatches.cs | 2909 +++++++++++ Harmony/MultiActionReversePatches.cs | 68 + Harmony/MultiBarrelPatches.cs | 155 + Harmony/Patches.cs | 1325 +++++ Harmony/RecoilPatch.cs | 156 + Harmony/SaveRescuePatches.cs | 6 + KFAttached/Animation.meta | 8 + KFAttached/Animation/DebugScripts.meta | 8 + .../DebugScripts/AnimatorActionIndexDebug.cs | 35 + .../AnimatorActionIndexDebug.cs.meta | 11 + KFAttached/Animation/MonoBehaviours.meta | 8 + .../AnimationAimRecoilReferences.cs | 32 + .../AnimationAimRecoilReferences.cs.meta | 11 + .../MonoBehaviours/AnimationDelayRender.cs | 212 + .../AnimationDelayRender.cs.meta | 11 + .../AnimationDelayRenderReference.cs | 24 + .../AnimationDelayRenderReference.cs.meta | 11 + .../MonoBehaviours/AnimationFiringEvents.cs | 31 + .../AnimationFiringEvents.cs.meta | 11 + .../MonoBehaviours/AnimationGraphBuilder.cs | 381 ++ .../AnimationGraphBuilder.cs.meta | 11 + .../AnimationProceduralRecoildAbs.cs | 6 + .../AnimationProceduralRecoildAbs.cs.meta | 11 + .../MonoBehaviours/AnimationRandomRecoil.cs | 163 + .../AnimationRandomRecoil.cs.meta | 11 + .../MonoBehaviours/AnimationRandomSound.cs | 97 + .../AnimationRandomSound.cs.meta | 11 + .../MonoBehaviours/AnimationReloadEvents.cs | 356 ++ .../AnimationReloadEvents.cs.meta | 11 + .../MonoBehaviours/AnimationSmokeParticle.cs | 17 + .../AnimationSmokeParticle.cs.meta | 11 + .../MonoBehaviours/AnimatorWrapper.meta | 8 + .../AnimatorWrapper/AnimatorWrapper.cs | 131 + .../AnimatorWrapper/AnimatorWrapper.cs.meta | 11 + .../AnimatorWrapper/AttachmentWrapper.cs | 443 ++ .../AnimatorWrapper/AttachmentWrapper.cs.meta | 11 + .../AnimatorWrapper/PlayableWrapper.cs | 92 + .../AnimatorWrapper/PlayableWrapper.cs.meta | 11 + .../MonoBehaviours/IAnimatorWrapper.cs | 73 + .../MonoBehaviours/IAnimatorWrapper.cs.meta | 11 + .../MonoBehaviours/IPlayableGraphRelated.cs | 7 + .../IPlayableGraphRelated.cs.meta | 11 + .../MonoBehaviours/RigWeightOverTime.cs | 123 + .../MonoBehaviours/RigWeightOverTime.cs.meta | 11 + .../Animation/StateMachineBehaviours.meta | 8 + .../AnimationAimRecoilResetState.cs | 14 + .../AnimationAimRecoilResetState.cs.meta | 11 + .../AnimationAmmoUpdateState.cs | 66 + .../AnimationAmmoUpdateState.cs.meta | 11 + .../AnimationCustomMeleeAttackState.cs | 266 + .../AnimationCustomMeleeAttackState.cs.meta | 11 + .../AnimationCustomReloadState.cs | 94 + .../AnimationCustomReloadState.cs.meta | 11 + .../AnimationInspectFix.cs | 71 + .../AnimationInspectFix.cs.meta | 11 + .../AnimationLockAction.cs | 41 + .../AnimationLockAction.cs.meta | 11 + .../AnimationMultiStageReloadState.cs | 85 + .../AnimationMultiStageReloadState.cs.meta | 11 + .../AnimationRandomRecoilState.cs | 12 + .../AnimationRandomRecoilState.cs.meta | 11 + .../AnimationResetRigWeightState.cs | 9 + .../AnimationResetRigWeightState.cs.meta | 11 + .../AnimationRigLayerController.cs | 63 + .../AnimationRigLayerController.cs.meta | 11 + .../AnimatorRandomSwitch.cs | 45 + .../AnimatorRandomSwitch.cs.meta | 11 + KFAttached/FPSPack.meta | 8 + KFAttached/FPSPack/Demo.meta | 8 + KFAttached/FPSPack/Demo/FPSDemoGUI.cs | 68 + KFAttached/FPSPack/Demo/FPSDemoGUI.cs.meta | 11 + KFAttached/FPSPack/Demo/FPSDemoReactivator.cs | 19 + .../FPSPack/Demo/FPSDemoReactivator.cs.meta | 11 + KFAttached/FPSPack/Demo/FPSFireManager.cs | 49 + .../FPSPack/Demo/FPSFireManager.cs.meta | 11 + KFAttached/FPSPack/Demo/MouseLock.cs | 22 + KFAttached/FPSPack/Demo/MouseLock.cs.meta | 11 + KFAttached/FPSPack/FPSLightCurves.cs | 47 + KFAttached/FPSPack/FPSLightCurves.cs.meta | 11 + KFAttached/FPSPack/FPSParticleSystemScaler.cs | 62 + .../FPSPack/FPSParticleSystemScaler.cs.meta | 11 + KFAttached/FPSPack/FPSRandomRotateAngle.cs | 29 + .../FPSPack/FPSRandomRotateAngle.cs.meta | 11 + KFAttached/FPSPack/FPSShaderColorGradient.cs | 61 + .../FPSPack/FPSShaderColorGradient.cs.meta | 11 + KFAttached/FPSPack/FPSShaderFloatCurves.cs | 57 + .../FPSPack/FPSShaderFloatCurves.cs.meta | 11 + KFAttached/FPSPack/MaterialType.cs | 22 + KFAttached/FPSPack/MaterialType.cs.meta | 11 + KFAttached/GG Camera Shake.meta | 8 + KFAttached/GG Camera Shake/Runtime.meta | 8 + .../GG Camera Shake/Runtime/Attenuator.cs | 66 + .../Runtime/Attenuator.cs.meta | 11 + .../GG Camera Shake/Runtime/BounceShake.cs | 133 + .../Runtime/BounceShake.cs.meta | 11 + .../Runtime/CameraShakePresets.cs | 113 + .../Runtime/CameraShakePresets.cs.meta | 11 + .../GG Camera Shake/Runtime/CameraShaker.cs | 98 + .../Runtime/CameraShaker.cs.meta | 11 + .../GG Camera Shake/Runtime/Displacement.cs | 98 + .../Runtime/Displacement.cs.meta | 11 + .../GG Camera Shake/Runtime/Envelope.cs | 168 + .../GG Camera Shake/Runtime/Envelope.cs.meta | 11 + .../GG Camera Shake/Runtime/ICameraShake.cs | 27 + .../Runtime/ICameraShake.cs.meta | 11 + .../GG Camera Shake/Runtime/KickShake.cs | 121 + .../GG Camera Shake/Runtime/KickShake.cs.meta | 11 + .../GG Camera Shake/Runtime/PerlinShake.cs | 144 + .../Runtime/PerlinShake.cs.meta | 11 + KFAttached/GG Camera Shake/Runtime/Power.cs | 24 + .../GG Camera Shake/Runtime/Power.cs.meta | 11 + KFAttached/KFCommonUtilityLib.asmdef | 20 + KFAttached/KFCommonUtilityLib.asmdef.meta | 7 + KFAttached/KFUtilAttached.meta | 8 + .../ApexWeaponHudControllerBase.cs | 154 + .../ApexWeaponHudControllerBase.cs.meta | 11 + .../KFUtilAttached/ChargeUpController.cs | 17 + .../KFUtilAttached/ChargeUpController.cs.meta | 11 + .../KFUtilAttached/MuzzlePositionBinding.cs | 33 + .../MuzzlePositionBinding.cs.meta | 11 + .../KFUtilAttached/RigActivationBinding.cs | 69 + .../RigActivationBinding.cs.meta | 11 + .../TransformActivationBinding.cs | 141 + .../TransformActivationBinding.cs.meta | 11 + .../KFUtilAttached/WeaponColorController.cs | 16 + .../WeaponColorController.cs.meta | 11 + .../WeaponColorControllerBase.cs | 6 + .../WeaponColorControllerBase.cs.meta | 11 + .../KFUtilAttached/WeaponDataController.cs | 24 + .../WeaponDataController.cs.meta | 11 + .../KFUtilAttached/WeaponDataHandlerBase.cs | 7 + .../WeaponDataHandlerBase.cs.meta | 11 + .../WeaponDataHandlerCanvasMask.cs | 51 + .../WeaponDataHandlerCanvasMask.cs.meta | 11 + .../WeaponDataHandlerIndicator.cs | 71 + .../WeaponDataHandlerIndicator.cs.meta | 11 + .../KFUtilAttached/WeaponDataHandlerTMP.cs | 17 + .../WeaponDataHandlerTMP.cs.meta | 11 + .../KFUtilAttached/WeaponLabelController.cs | 24 + .../WeaponLabelController.cs.meta | 11 + .../WeaponLabelControllerBase.cs | 7 + .../WeaponLabelControllerBase.cs.meta | 11 + .../WeaponLabelControllerBatch.cs | 36 + .../WeaponLabelControllerBatch.cs.meta | 11 + .../WeaponLabelControllerChargeUp.cs | 61 + .../WeaponLabelControllerChargeUp.cs.meta | 11 + .../WeaponLabelControllerDevotion.cs | 25 + .../WeaponLabelControllerDevotion.cs.meta | 11 + .../KFUtilAttached/WeaponTextProController.cs | 25 + .../WeaponTextProController.cs.meta | 11 + KFAttached/LeanTween.meta | 8 + KFAttached/LeanTween/Framework.meta | 8 + KFAttached/LeanTween/Framework/LTDescr.cs | 2695 ++++++++++ .../LeanTween/Framework/LTDescr.cs.meta | 11 + .../LeanTween/Framework/LTDescrOptional.cs | 99 + .../Framework/LTDescrOptional.cs.meta | 11 + KFAttached/LeanTween/Framework/LTSeq.cs | 243 + KFAttached/LeanTween/Framework/LTSeq.cs.meta | 11 + KFAttached/LeanTween/Framework/LeanAudio.cs | 471 ++ .../LeanTween/Framework/LeanAudio.cs.meta | 11 + KFAttached/LeanTween/Framework/LeanSmooth.cs | 363 ++ .../LeanTween/Framework/LeanSmooth.cs.meta | 11 + KFAttached/LeanTween/Framework/LeanTest.cs | 146 + .../LeanTween/Framework/LeanTest.cs.meta | 11 + KFAttached/LeanTween/Framework/LeanTween.cs | 4581 +++++++++++++++++ .../LeanTween/Framework/LeanTween.cs.meta | 11 + .../LeanTween/Framework/LeanTweenExt.cs | 188 + .../LeanTween/Framework/LeanTweenExt.cs.meta | 11 + KFAttached/LeanTween/License.txt | 31 + KFAttached/LeanTween/License.txt.meta | 7 + KFAttached/Misc.meta | 8 + KFAttached/Misc/AimReference.cs | 49 + KFAttached/Misc/AimReference.cs.meta | 11 + KFAttached/Misc/AimReferenceGroup.cs | 62 + KFAttached/Misc/AimReferenceGroup.cs.meta | 11 + KFAttached/Misc/AttachmentReference.cs | 7 + KFAttached/Misc/AttachmentReference.cs.meta | 11 + .../Misc/AttachmentReferenceAppended.cs | 45 + .../Misc/AttachmentReferenceAppended.cs.meta | 11 + KFAttached/Misc/AudioSourceGroup.cs | 15 + KFAttached/Misc/AudioSourceGroup.cs.meta | 11 + KFAttached/Misc/IgnoreTint.cs | 6 + KFAttached/Misc/IgnoreTint.cs.meta | 11 + KFAttached/Misc/ItemAnimatorUpdate.cs | 31 + KFAttached/Misc/ItemAnimatorUpdate.cs.meta | 11 + KFAttached/Misc/PlayerRigLateUpdate.cs | 34 + KFAttached/Misc/PlayerRigLateUpdate.cs.meta | 11 + KFAttached/Misc/ScopeBase.cs | 5 + KFAttached/Misc/ScopeBase.cs.meta | 11 + KFAttached/Misc/WeaponCameraFollow.cs | 62 + KFAttached/Misc/WeaponCameraFollow.cs.meta | 11 + KFAttached/Render.meta | 8 + KFAttached/Render/BokehBlurTargetRef.cs | 12 + KFAttached/Render/BokehBlurTargetRef.cs.meta | 11 + KFAttached/Render/MagnifyScope.cs | 405 ++ KFAttached/Render/MagnifyScope.cs.meta | 11 + KFAttached/Render/MagnifyScopeTargetRef.cs | 38 + .../Render/MagnifyScopeTargetRef.cs.meta | 11 + KFAttached/RigAdaptors.meta | 8 + KFAttached/RigAdaptors/Adaptors.meta | 8 + .../Adaptors/BlendConstraintAdaptor.cs | 56 + .../Adaptors/BlendConstraintAdaptor.cs.meta | 11 + .../Adaptors/ChainIKConstraintAdaptor.cs | 56 + .../Adaptors/ChainIKConstraintAdaptor.cs.meta | 11 + .../Adaptors/DampedTransformAdaptor.cs | 38 + .../Adaptors/DampedTransformAdaptor.cs.meta | 11 + KFAttached/RigAdaptors/Adaptors/Data.meta | 8 + .../RigAdaptors/Adaptors/Data/TwistNode.cs | 22 + .../Adaptors/Data/TwistNode.cs.meta | 11 + .../Adaptors/MultiAimConstraintAdaptor.cs | 68 + .../MultiAimConstraintAdaptor.cs.meta | 11 + .../Adaptors/MultiParentConstraintAdaptor.cs | 47 + .../MultiParentConstraintAdaptor.cs.meta | 11 + .../MultiPositionConstraintAdaptor.cs | 42 + .../MultiPositionConstraintAdaptor.cs.meta | 11 + .../MultiReferentialConstraintAdaptor.cs | 29 + .../MultiReferentialConstraintAdaptor.cs.meta | 11 + .../MultiRotationConstraintAdaptor.cs | 42 + .../MultiRotationConstraintAdaptor.cs.meta | 11 + .../Adaptors/OverrideTransformAdaptor.cs | 48 + .../Adaptors/OverrideTransformAdaptor.cs.meta | 11 + .../RigAdaptors/Adaptors/RigAdaptorAbs.cs | 34 + .../Adaptors/RigAdaptorAbs.cs.meta | 11 + .../Adaptors/TwistChainConstraintAdaptor.cs | 40 + .../TwistChainConstraintAdaptor.cs.meta | 11 + .../Adaptors/TwistCorrectionAdaptor.cs | 50 + .../Adaptors/TwistCorrectionAdaptor.cs.meta | 11 + .../Adaptors/TwoBoneIKConstraintAdaptor.cs | 59 + .../TwoBoneIKConstraintAdaptor.cs.meta | 11 + KFAttached/RigAdaptors/AnimationTargetsAbs.cs | 542 ++ .../RigAdaptors/AnimationTargetsAbs.cs.meta | 11 + KFAttached/RigAdaptors/PlayGraphTargets.cs | 165 + .../RigAdaptors/PlayGraphTargets.cs.meta | 11 + KFAttached/RigAdaptors/ReverseAdaptors.meta | 8 + .../BlendConstraintReverseAdaptor.cs | 56 + .../BlendConstraintReverseAdaptor.cs.meta | 11 + .../ChainIKConstraintReverseAdaptor.cs | 56 + .../ChainIKConstraintReverseAdaptor.cs.meta | 11 + .../DampedTransformReverseAdaptor.cs | 38 + .../DampedTransformReverseAdaptor.cs.meta | 11 + .../MultiAimConstraintReverseAdaptor.cs | 69 + .../MultiAimConstraintReverseAdaptor.cs.meta | 11 + .../MultiParentConstraintReverseAdaptor.cs | 49 + ...ultiParentConstraintReverseAdaptor.cs.meta | 11 + .../MultiPositionConstraintReverseAdaptor.cs | 44 + ...tiPositionConstraintReverseAdaptor.cs.meta | 11 + ...ultiReferentialConstraintReverseAdaptor.cs | 37 + ...eferentialConstraintReverseAdaptor.cs.meta | 11 + .../MultiRotationConstraintReverseAdaptor.cs | 44 + ...tiRotationConstraintReverseAdaptor.cs.meta | 11 + .../OverrideTransformReverseAdaptor.cs | 48 + .../OverrideTransformReverseAdaptor.cs.meta | 11 + .../TwistChainConstraintReverseAdaptor.cs | 40 + ...TwistChainConstraintReverseAdaptor.cs.meta | 11 + .../TwistCorrectionReverseAdaptor.cs | 15 + .../TwistCorrectionReverseAdaptor.cs.meta | 11 + .../TwoBoneIKConstraintReverseAdaptor.cs | 59 + .../TwoBoneIKConstraintReverseAdaptor.cs.meta | 11 + KFAttached/RigAdaptors/RigConverter.cs | 309 ++ KFAttached/RigAdaptors/RigConverter.cs.meta | 11 + KFAttached/RigAdaptors/RigConverterRole.cs | 14 + .../RigAdaptors/RigConverterRole.cs.meta | 11 + KFAttached/RigAdaptors/RigTargets.cs | 183 + KFAttached/RigAdaptors/RigTargets.cs.meta | 11 + KFAttached/RigAdaptors/Utils.meta | 8 + .../RigAdaptors/Utils/InventorySlotGurad.cs | 25 + .../Utils/InventorySlotGurad.cs.meta | 11 + KFAttached/RigAdaptors/Utils/KFExtensions.cs | 431 ++ .../RigAdaptors/Utils/KFExtensions.cs.meta | 11 + .../RigAdaptors/Utils/QuaternionUtil.cs | 64 + .../RigAdaptors/Utils/QuaternionUtil.cs.meta | 11 + KFCommonUtilityLib.csproj | 718 +++ KFCommonUtilityLib.dll | Bin 0 -> 721408 bytes KFCommonUtilityLib.pdb | Bin 0 -> 244936 bytes ModInfo.xml | 9 + ModSettings.xml | 28 + Properties/AssemblyInfo.cs | 35 + README.md | 144 + Resources/PIPScope.unity3d | Bin 0 -> 23215 bytes .../Attributes/ActionDataTargetAttribute.cs | 18 + Scripts/Attributes/MethodTargetAttribute.cs | 45 + Scripts/Attributes/PatchTargetAttribute.cs | 16 + .../TypeTargetExtensionAttribute.cs | 14 + .../ConsoleCmd/ConsoleCmdCalibrateWeapon.cs | 175 + .../ConsoleCmdListParticleScripts.cs | 57 + .../ConsoleCmdMultiActionItemValueDebug.cs | 59 + .../ConsoleCmd/ConsoleCmdPlayerDebugInfo.cs | 59 + .../ConsoleCmd/ConsoleCmdPrintLocalCache.cs | 41 + Scripts/ConsoleCmd/ConsoleCmdReloadLog.cs | 28 + Scripts/FbxExporter07.cs | 753 +++ Scripts/Global/CustomEnums.cs | 28 + Scripts/Input/PlayerActionKFLib.cs | 46 + Scripts/Input/PlayerActionToggleFireMode.cs | 38 + Scripts/Input/PlayerActionToggleMode.cs | 38 + Scripts/Items/ItemActionAltMode.cs | 208 + Scripts/Items/ItemActionHoldOpen.cs | 172 + Scripts/Items/ItemActionRampUp.cs | 188 + Scripts/Items/ItemActionRechargeable.cs | 76 + .../Items/Modular/ActionModuleAlternative.cs | 261 + .../Modular/ActionModuleAnimationLocked.cs | 36 + .../ActionModuleCustomAnimationDelay.cs | 135 + .../Modular/ActionModuleDisplayAsBuff.cs | 78 + .../Items/Modular/ActionModuleDynamicGraze.cs | 67 + .../Modular/ActionModuleDynamicMuzzleFlash.cs | 84 + .../Modular/ActionModuleDynamicSensitivity.cs | 89 + .../Items/Modular/ActionModuleErgoAffected.cs | 153 + .../Modular/ActionModuleFireModeSelector.cs | 335 ++ Scripts/Items/Modular/ActionModuleHoldOpen.cs | 85 + .../Items/Modular/ActionModuleInspectable.cs | 24 + .../Modular/ActionModuleInterruptReload.cs | 225 + .../Modular/ActionModuleInvariableRPM.cs | 60 + .../Modular/ActionModuleLocalPassiveCache.cs | 105 + .../Items/Modular/ActionModuleMetaConsumer.cs | 178 + .../Modular/ActionModuleMetaRecharger.cs | 166 + .../Modular/ActionModuleMultiActionFix.cs | 222 + .../Items/Modular/ActionModuleMultiBarrel.cs | 302 ++ Scripts/Items/Modular/ActionModuleRampUp.cs | 276 + Scripts/Items/Modular/ActionModuleTagged.cs | 30 + .../Modular/ActionModuleTranspilerTest.cs | 48 + .../Items/Modular/ActionModuleVariableZoom.cs | 73 + .../ModularActions/ActionModuleAlternative.cs | 261 + .../ActionModuleAnimationLocked.cs | 36 + .../ActionModuleCustomAnimationDelay.cs | 135 + .../ActionModuleDisplayAsBuff.cs | 78 + .../ActionModuleDynamicGraze.cs | 67 + .../ActionModuleDynamicMuzzleFlash.cs | 84 + .../ActionModuleDynamicSensitivity.cs | 93 + .../ActionModuleErgoAffected.cs | 157 + .../ActionModuleFireModeSelector.cs | 336 ++ .../ModularActions/ActionModuleHoldOpen.cs | 85 + .../ModularActions/ActionModuleInspectable.cs | 24 + .../ActionModuleInterruptReload.cs | 225 + .../ActionModuleInvariableRPM.cs | 60 + .../ActionModuleLocalPassiveCache.cs | 105 + .../ActionModuleMetaConsumer.cs | 178 + .../ActionModuleMetaRecharger.cs | 166 + .../ActionModuleMultiActionFix.cs | 222 + .../ModularActions/ActionModuleMultiBarrel.cs | 302 ++ .../ActionModuleProceduralAiming.cs | 271 + .../ModularActions/ActionModuleRampUp.cs | 276 + .../ModularActions/ActionModuleTagged.cs | 30 + .../ActionModuleTranspilerTest.cs | 48 + .../ActionModuleVariableZoom.cs | 260 + .../ModularClasses/ItemModuleSortable.cs | 87 + .../ModularClasses/ItemModuleVariableZoom.cs | 6 + .../MinEventActionAddBuffToTargetAndSelf.cs | 12 + .../MinEventActionAddItemToInventory.cs | 21 + .../MinEventActionAddRoundsToInventory.cs | 16 + .../MinEventActionAddRoundsToMagazine.cs | 28 + .../MinEventActionAmmoAccessBase.cs | 56 + .../MinEventActionAttachPrefabToEntitySync.cs | 81 + .../MinEventActionBroadcastPlaySoundLocal.cs | 8 + .../MinEventActionCVarExpression.cs | 248 + ...tionDecreaseProgressionLevelAndRefundSP.cs | 25 + .../MinEventActionItemAccessBase.cs | 23 + .../MinEventActionItemCountRandomBase.cs | 60 + .../MinEventActionModifyCVarWithLocalCache.cs | 72 + .../MinEventActionModifyCVarWithSelfRef.cs | 48 + .../MinEventActionOverrideZoomFOV.cs | 101 + .../MinEventActionRemoteHoldingBase.cs | 31 + .../MinEventActionRemoveItemFromInventory.cs | 15 + .../MinEventActionRemovePrefabFromHeldItem.cs | 46 + ...MinEventActionRemoveRoundsFromInventory.cs | 19 + .../MinEventActionSetAmmoOnWeaponLabel.cs | 64 + .../MinEventActionSetMetadataOnWeaponLabel.cs | 64 + .../MinEventActionSetPassiveOnWeaponLabel.cs | 64 + .../MinEventActionSetStringOnWeaponLabel.cs | 59 + .../MinEventActionSetWeaponLabelColor.cs | 51 + .../MinEventActionUpdateLocalCache.cs | 49 + .../NetPackageEntityActionIndex.cs | 42 + .../NetPackageEntitySpawnWithCVar.cs | 81 + Scripts/NetPackages/NetPackageFixedReload.cs | 49 + .../NetPackageRemoteAttachPrefab.cs | 69 + .../NetPackageSyncWeaponLabelColor.cs | 117 + .../NetPackageSyncWeaponLabelText.cs | 82 + Scripts/Requirements/ActionHasTags.cs | 52 + Scripts/Requirements/ActionIndexIs.cs | 31 + Scripts/Requirements/AmmoIndexIs.cs | 44 + Scripts/Requirements/FireModeIs.cs | 32 + Scripts/Requirements/HoldingActionIndexIs.cs | 9 + Scripts/Requirements/HoldingAmmoIndexIs.cs | 8 + Scripts/Requirements/HoldingFireModeIs.cs | 33 + Scripts/Requirements/IsActionUnlocked.cs | 28 + .../IsHoldingItemModificationActivated.cs | 64 + Scripts/Requirements/IsInJeep.cs | 15 + Scripts/Requirements/IsLocal.cs | 7 + .../Requirements/IsModificationActivated.cs | 63 + Scripts/Requirements/ItemActionIndexIs.cs | 7 + Scripts/Requirements/ItemInInventory.cs | 33 + Scripts/Requirements/PercentInHoldingItem.cs | 17 + Scripts/Requirements/PercentInMagazine.cs | 14 + Scripts/Requirements/RoundsInHoldingItem.cs | 17 + Scripts/Requirements/RoundsInInventory.cs | 32 + Scripts/Requirements/RoundsInMagazineBase.cs | 21 + .../StaticManagers/AnimationRiggingManager.cs | 437 ++ .../BackgroundInventoryUpdateManager.cs | 117 + .../StaticManagers/CustomEffectEnumManager.cs | 215 + .../StaticManagers/DelayLoadModuleManager.cs | 95 + .../StaticManagers/ItemActionModuleManager.cs | 937 ++++ .../StaticManagers/LocalItemTagsManager.cs | 257 + Scripts/StaticManagers/MultiActionManager.cs | 600 +++ Scripts/StaticManagers/RecoilManager.cs | 370 ++ Scripts/Utilities/EasingFunctions.cs | 125 + Scripts/Utilities/EntityInventoryExtension.cs | 67 + .../ExpressionParser/ExpressionParser.cs | 424 ++ .../ExpressionParser/FloatExpressionParser.cs | 38 + .../ExpressionParser/Sprache/CommentParser.cs | 124 + .../ExpressionParser/Sprache/IComment.cs | 43 + .../ExpressionParser/Sprache/ICommentedOfT.cs | 26 + .../ExpressionParser/Sprache/IInput.cs | 53 + .../Sprache/IPositionAware.cs | 18 + .../ExpressionParser/Sprache/IResultOfT.cs | 36 + .../ExpressionParser/Sprache/ITextSpanOfT.cs | 29 + .../ExpressionParser/Sprache/Input.cs | 156 + .../ExpressionParser/Sprache/Option.cs | 145 + .../Sprache/Parse.Commented.cs | 126 + .../Sprache/Parse.Optional.cs | 80 + .../Sprache/Parse.Positioned.cs | 27 + .../Sprache/Parse.Primitives.cs | 34 + .../Sprache/Parse.Sequence.cs | 158 + .../ExpressionParser/Sprache/Parse.cs | 782 +++ .../Sprache/ParseException.cs | 50 + .../ExpressionParser/Sprache/ParserOfT.cs | 54 + .../ExpressionParser/Sprache/Position.cs | 136 + .../ExpressionParser/Sprache/Result.cs | 111 + .../ExpressionParser/Sprache/ResultHelper.cs | 26 + .../Sprache/StringExtensions.cs | 32 + .../ExpressionParser/Sprache/licence.txt | 21 + Scripts/Utilities/Modular/IModuleProcessor.cs | 19 + .../Modular/ItemActionDataModuleProcessor.cs | 80 + .../Modular/ItemActionModuleManager.cs | 104 + .../Modular/ItemActionModuleProcessor.cs | 157 + .../Modular/ItemClassModuleManager.cs | 104 + .../Modular/ItemClassModuleProcessor.cs | 33 + Scripts/Utilities/Modular/ModuleManagers.cs | 262 + .../Utilities/Modular/ModuleManipulator.cs | 646 +++ Scripts/Utilities/Modular/ModuleUtils.cs | 67 + Scripts/Utilities/MonoCecilExtensions.cs | 1685 ++++++ .../MultiActionProjectileRewrites.cs | 738 +++ Scripts/Utilities/MultiActionUtils.cs | 445 ++ Scripts/Utilities/SaveTextureToFileUtility.cs | 134 + Scripts/Utilities/TemporaryMuzzleFlash.cs | 22 + Scripts/Utilities/TypeBasedUID.cs | 5 + TreeCollections.dll | Bin 0 -> 74752 bytes ...ex-7D2D-mods main 0-KFCommonUtilityLib.zip | Bin 0 -> 3599688 bytes 470 files changed, 51966 insertions(+) create mode 100644 .gitignore create mode 100644 Config/Localization.txt create mode 100644 Config/buffs.xml create mode 100644 CustomPlayerActionManager.dll create mode 100644 CustomPlayerActionManager.pdb create mode 100644 DOTween.Modules.dll create mode 100644 DOTween.Modules.pdb create mode 100644 DOTween.XML create mode 100644 DOTween.dll create mode 100644 DOTween.dll.mdb create mode 100644 DelayLoad/FullautoLauncherAnimationRiggingCompatibilityPatch.dll create mode 100644 DelayLoad/FullautoLauncherAnimationRiggingCompatibilityPatch.pdb create mode 100644 DelayLoad/SMXMultiActionCompatibilityPatch.dll create mode 100644 DelayLoad/SMXMultiActionCompatibilityPatch.pdb create mode 100644 GearsAPI.dll create mode 100644 Harmony/AnimationRiggingPatches.cs create mode 100644 Harmony/BackgroundInventoryUpdatePatch.cs create mode 100644 Harmony/DamagePatches.cs create mode 100644 Harmony/DisplayMetaAsBuffPatch.cs create mode 100644 Harmony/FPVLegPatches.cs create mode 100644 Harmony/HideMarkerOnAimPatch.cs create mode 100644 Harmony/Init.cs create mode 100644 Harmony/InvariableRPMPatches.cs create mode 100644 Harmony/ItemActionModulePatch.cs create mode 100644 Harmony/ModularPatches.cs create mode 100644 Harmony/MultiActionPatches.cs create mode 100644 Harmony/MultiActionReversePatches.cs create mode 100644 Harmony/MultiBarrelPatches.cs create mode 100644 Harmony/Patches.cs create mode 100644 Harmony/RecoilPatch.cs create mode 100644 Harmony/SaveRescuePatches.cs create mode 100644 KFAttached/Animation.meta create mode 100644 KFAttached/Animation/DebugScripts.meta create mode 100644 KFAttached/Animation/DebugScripts/AnimatorActionIndexDebug.cs create mode 100644 KFAttached/Animation/DebugScripts/AnimatorActionIndexDebug.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationAimRecoilReferences.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationAimRecoilReferences.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationDelayRender.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationDelayRender.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationDelayRenderReference.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationDelayRenderReference.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationFiringEvents.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationFiringEvents.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationGraphBuilder.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationGraphBuilder.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationProceduralRecoildAbs.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationProceduralRecoildAbs.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationRandomRecoil.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationRandomRecoil.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationRandomSound.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationRandomSound.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationReloadEvents.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationReloadEvents.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationSmokeParticle.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimationSmokeParticle.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimatorWrapper.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AnimatorWrapper.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AnimatorWrapper.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AttachmentWrapper.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AttachmentWrapper.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/AnimatorWrapper/PlayableWrapper.cs create mode 100644 KFAttached/Animation/MonoBehaviours/AnimatorWrapper/PlayableWrapper.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/IAnimatorWrapper.cs create mode 100644 KFAttached/Animation/MonoBehaviours/IAnimatorWrapper.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/IPlayableGraphRelated.cs create mode 100644 KFAttached/Animation/MonoBehaviours/IPlayableGraphRelated.cs.meta create mode 100644 KFAttached/Animation/MonoBehaviours/RigWeightOverTime.cs create mode 100644 KFAttached/Animation/MonoBehaviours/RigWeightOverTime.cs.meta create mode 100644 KFAttached/Animation/StateMachineBehaviours.meta create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationAimRecoilResetState.cs create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationAimRecoilResetState.cs.meta create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationAmmoUpdateState.cs create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationAmmoUpdateState.cs.meta create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationCustomMeleeAttackState.cs create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationCustomMeleeAttackState.cs.meta create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationCustomReloadState.cs create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationCustomReloadState.cs.meta create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationInspectFix.cs create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationInspectFix.cs.meta create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationLockAction.cs create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationLockAction.cs.meta create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationMultiStageReloadState.cs create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationMultiStageReloadState.cs.meta create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationRandomRecoilState.cs create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationRandomRecoilState.cs.meta create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationResetRigWeightState.cs create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationResetRigWeightState.cs.meta create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationRigLayerController.cs create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimationRigLayerController.cs.meta create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimatorRandomSwitch.cs create mode 100644 KFAttached/Animation/StateMachineBehaviours/AnimatorRandomSwitch.cs.meta create mode 100644 KFAttached/FPSPack.meta create mode 100644 KFAttached/FPSPack/Demo.meta create mode 100644 KFAttached/FPSPack/Demo/FPSDemoGUI.cs create mode 100644 KFAttached/FPSPack/Demo/FPSDemoGUI.cs.meta create mode 100644 KFAttached/FPSPack/Demo/FPSDemoReactivator.cs create mode 100644 KFAttached/FPSPack/Demo/FPSDemoReactivator.cs.meta create mode 100644 KFAttached/FPSPack/Demo/FPSFireManager.cs create mode 100644 KFAttached/FPSPack/Demo/FPSFireManager.cs.meta create mode 100644 KFAttached/FPSPack/Demo/MouseLock.cs create mode 100644 KFAttached/FPSPack/Demo/MouseLock.cs.meta create mode 100644 KFAttached/FPSPack/FPSLightCurves.cs create mode 100644 KFAttached/FPSPack/FPSLightCurves.cs.meta create mode 100644 KFAttached/FPSPack/FPSParticleSystemScaler.cs create mode 100644 KFAttached/FPSPack/FPSParticleSystemScaler.cs.meta create mode 100644 KFAttached/FPSPack/FPSRandomRotateAngle.cs create mode 100644 KFAttached/FPSPack/FPSRandomRotateAngle.cs.meta create mode 100644 KFAttached/FPSPack/FPSShaderColorGradient.cs create mode 100644 KFAttached/FPSPack/FPSShaderColorGradient.cs.meta create mode 100644 KFAttached/FPSPack/FPSShaderFloatCurves.cs create mode 100644 KFAttached/FPSPack/FPSShaderFloatCurves.cs.meta create mode 100644 KFAttached/FPSPack/MaterialType.cs create mode 100644 KFAttached/FPSPack/MaterialType.cs.meta create mode 100644 KFAttached/GG Camera Shake.meta create mode 100644 KFAttached/GG Camera Shake/Runtime.meta create mode 100644 KFAttached/GG Camera Shake/Runtime/Attenuator.cs create mode 100644 KFAttached/GG Camera Shake/Runtime/Attenuator.cs.meta create mode 100644 KFAttached/GG Camera Shake/Runtime/BounceShake.cs create mode 100644 KFAttached/GG Camera Shake/Runtime/BounceShake.cs.meta create mode 100644 KFAttached/GG Camera Shake/Runtime/CameraShakePresets.cs create mode 100644 KFAttached/GG Camera Shake/Runtime/CameraShakePresets.cs.meta create mode 100644 KFAttached/GG Camera Shake/Runtime/CameraShaker.cs create mode 100644 KFAttached/GG Camera Shake/Runtime/CameraShaker.cs.meta create mode 100644 KFAttached/GG Camera Shake/Runtime/Displacement.cs create mode 100644 KFAttached/GG Camera Shake/Runtime/Displacement.cs.meta create mode 100644 KFAttached/GG Camera Shake/Runtime/Envelope.cs create mode 100644 KFAttached/GG Camera Shake/Runtime/Envelope.cs.meta create mode 100644 KFAttached/GG Camera Shake/Runtime/ICameraShake.cs create mode 100644 KFAttached/GG Camera Shake/Runtime/ICameraShake.cs.meta create mode 100644 KFAttached/GG Camera Shake/Runtime/KickShake.cs create mode 100644 KFAttached/GG Camera Shake/Runtime/KickShake.cs.meta create mode 100644 KFAttached/GG Camera Shake/Runtime/PerlinShake.cs create mode 100644 KFAttached/GG Camera Shake/Runtime/PerlinShake.cs.meta create mode 100644 KFAttached/GG Camera Shake/Runtime/Power.cs create mode 100644 KFAttached/GG Camera Shake/Runtime/Power.cs.meta create mode 100644 KFAttached/KFCommonUtilityLib.asmdef create mode 100644 KFAttached/KFCommonUtilityLib.asmdef.meta create mode 100644 KFAttached/KFUtilAttached.meta create mode 100644 KFAttached/KFUtilAttached/ApexWeaponHudControllerBase.cs create mode 100644 KFAttached/KFUtilAttached/ApexWeaponHudControllerBase.cs.meta create mode 100644 KFAttached/KFUtilAttached/ChargeUpController.cs create mode 100644 KFAttached/KFUtilAttached/ChargeUpController.cs.meta create mode 100644 KFAttached/KFUtilAttached/MuzzlePositionBinding.cs create mode 100644 KFAttached/KFUtilAttached/MuzzlePositionBinding.cs.meta create mode 100644 KFAttached/KFUtilAttached/RigActivationBinding.cs create mode 100644 KFAttached/KFUtilAttached/RigActivationBinding.cs.meta create mode 100644 KFAttached/KFUtilAttached/TransformActivationBinding.cs create mode 100644 KFAttached/KFUtilAttached/TransformActivationBinding.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponColorController.cs create mode 100644 KFAttached/KFUtilAttached/WeaponColorController.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponColorControllerBase.cs create mode 100644 KFAttached/KFUtilAttached/WeaponColorControllerBase.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponDataController.cs create mode 100644 KFAttached/KFUtilAttached/WeaponDataController.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponDataHandlerBase.cs create mode 100644 KFAttached/KFUtilAttached/WeaponDataHandlerBase.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponDataHandlerCanvasMask.cs create mode 100644 KFAttached/KFUtilAttached/WeaponDataHandlerCanvasMask.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponDataHandlerIndicator.cs create mode 100644 KFAttached/KFUtilAttached/WeaponDataHandlerIndicator.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponDataHandlerTMP.cs create mode 100644 KFAttached/KFUtilAttached/WeaponDataHandlerTMP.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponLabelController.cs create mode 100644 KFAttached/KFUtilAttached/WeaponLabelController.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponLabelControllerBase.cs create mode 100644 KFAttached/KFUtilAttached/WeaponLabelControllerBase.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponLabelControllerBatch.cs create mode 100644 KFAttached/KFUtilAttached/WeaponLabelControllerBatch.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponLabelControllerChargeUp.cs create mode 100644 KFAttached/KFUtilAttached/WeaponLabelControllerChargeUp.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponLabelControllerDevotion.cs create mode 100644 KFAttached/KFUtilAttached/WeaponLabelControllerDevotion.cs.meta create mode 100644 KFAttached/KFUtilAttached/WeaponTextProController.cs create mode 100644 KFAttached/KFUtilAttached/WeaponTextProController.cs.meta create mode 100644 KFAttached/LeanTween.meta create mode 100644 KFAttached/LeanTween/Framework.meta create mode 100644 KFAttached/LeanTween/Framework/LTDescr.cs create mode 100644 KFAttached/LeanTween/Framework/LTDescr.cs.meta create mode 100644 KFAttached/LeanTween/Framework/LTDescrOptional.cs create mode 100644 KFAttached/LeanTween/Framework/LTDescrOptional.cs.meta create mode 100644 KFAttached/LeanTween/Framework/LTSeq.cs create mode 100644 KFAttached/LeanTween/Framework/LTSeq.cs.meta create mode 100644 KFAttached/LeanTween/Framework/LeanAudio.cs create mode 100644 KFAttached/LeanTween/Framework/LeanAudio.cs.meta create mode 100644 KFAttached/LeanTween/Framework/LeanSmooth.cs create mode 100644 KFAttached/LeanTween/Framework/LeanSmooth.cs.meta create mode 100644 KFAttached/LeanTween/Framework/LeanTest.cs create mode 100644 KFAttached/LeanTween/Framework/LeanTest.cs.meta create mode 100644 KFAttached/LeanTween/Framework/LeanTween.cs create mode 100644 KFAttached/LeanTween/Framework/LeanTween.cs.meta create mode 100644 KFAttached/LeanTween/Framework/LeanTweenExt.cs create mode 100644 KFAttached/LeanTween/Framework/LeanTweenExt.cs.meta create mode 100644 KFAttached/LeanTween/License.txt create mode 100644 KFAttached/LeanTween/License.txt.meta create mode 100644 KFAttached/Misc.meta create mode 100644 KFAttached/Misc/AimReference.cs create mode 100644 KFAttached/Misc/AimReference.cs.meta create mode 100644 KFAttached/Misc/AimReferenceGroup.cs create mode 100644 KFAttached/Misc/AimReferenceGroup.cs.meta create mode 100644 KFAttached/Misc/AttachmentReference.cs create mode 100644 KFAttached/Misc/AttachmentReference.cs.meta create mode 100644 KFAttached/Misc/AttachmentReferenceAppended.cs create mode 100644 KFAttached/Misc/AttachmentReferenceAppended.cs.meta create mode 100644 KFAttached/Misc/AudioSourceGroup.cs create mode 100644 KFAttached/Misc/AudioSourceGroup.cs.meta create mode 100644 KFAttached/Misc/IgnoreTint.cs create mode 100644 KFAttached/Misc/IgnoreTint.cs.meta create mode 100644 KFAttached/Misc/ItemAnimatorUpdate.cs create mode 100644 KFAttached/Misc/ItemAnimatorUpdate.cs.meta create mode 100644 KFAttached/Misc/PlayerRigLateUpdate.cs create mode 100644 KFAttached/Misc/PlayerRigLateUpdate.cs.meta create mode 100644 KFAttached/Misc/ScopeBase.cs create mode 100644 KFAttached/Misc/ScopeBase.cs.meta create mode 100644 KFAttached/Misc/WeaponCameraFollow.cs create mode 100644 KFAttached/Misc/WeaponCameraFollow.cs.meta create mode 100644 KFAttached/Render.meta create mode 100644 KFAttached/Render/BokehBlurTargetRef.cs create mode 100644 KFAttached/Render/BokehBlurTargetRef.cs.meta create mode 100644 KFAttached/Render/MagnifyScope.cs create mode 100644 KFAttached/Render/MagnifyScope.cs.meta create mode 100644 KFAttached/Render/MagnifyScopeTargetRef.cs create mode 100644 KFAttached/Render/MagnifyScopeTargetRef.cs.meta create mode 100644 KFAttached/RigAdaptors.meta create mode 100644 KFAttached/RigAdaptors/Adaptors.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/BlendConstraintAdaptor.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/BlendConstraintAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/ChainIKConstraintAdaptor.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/ChainIKConstraintAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/DampedTransformAdaptor.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/DampedTransformAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/Data.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/Data/TwistNode.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/Data/TwistNode.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/MultiAimConstraintAdaptor.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/MultiAimConstraintAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/MultiParentConstraintAdaptor.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/MultiParentConstraintAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/MultiPositionConstraintAdaptor.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/MultiPositionConstraintAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/MultiReferentialConstraintAdaptor.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/MultiReferentialConstraintAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/MultiRotationConstraintAdaptor.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/MultiRotationConstraintAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/OverrideTransformAdaptor.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/OverrideTransformAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/RigAdaptorAbs.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/RigAdaptorAbs.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/TwistChainConstraintAdaptor.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/TwistChainConstraintAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/TwistCorrectionAdaptor.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/TwistCorrectionAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/Adaptors/TwoBoneIKConstraintAdaptor.cs create mode 100644 KFAttached/RigAdaptors/Adaptors/TwoBoneIKConstraintAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/AnimationTargetsAbs.cs create mode 100644 KFAttached/RigAdaptors/AnimationTargetsAbs.cs.meta create mode 100644 KFAttached/RigAdaptors/PlayGraphTargets.cs create mode 100644 KFAttached/RigAdaptors/PlayGraphTargets.cs.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/BlendConstraintReverseAdaptor.cs create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/BlendConstraintReverseAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/ChainIKConstraintReverseAdaptor.cs create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/ChainIKConstraintReverseAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/DampedTransformReverseAdaptor.cs create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/DampedTransformReverseAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/MultiAimConstraintReverseAdaptor.cs create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/MultiAimConstraintReverseAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/MultiParentConstraintReverseAdaptor.cs create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/MultiParentConstraintReverseAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/MultiPositionConstraintReverseAdaptor.cs create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/MultiPositionConstraintReverseAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/MultiReferentialConstraintReverseAdaptor.cs create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/MultiReferentialConstraintReverseAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/MultiRotationConstraintReverseAdaptor.cs create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/MultiRotationConstraintReverseAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/OverrideTransformReverseAdaptor.cs create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/OverrideTransformReverseAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/TwistChainConstraintReverseAdaptor.cs create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/TwistChainConstraintReverseAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/TwistCorrectionReverseAdaptor.cs create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/TwistCorrectionReverseAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/TwoBoneIKConstraintReverseAdaptor.cs create mode 100644 KFAttached/RigAdaptors/ReverseAdaptors/TwoBoneIKConstraintReverseAdaptor.cs.meta create mode 100644 KFAttached/RigAdaptors/RigConverter.cs create mode 100644 KFAttached/RigAdaptors/RigConverter.cs.meta create mode 100644 KFAttached/RigAdaptors/RigConverterRole.cs create mode 100644 KFAttached/RigAdaptors/RigConverterRole.cs.meta create mode 100644 KFAttached/RigAdaptors/RigTargets.cs create mode 100644 KFAttached/RigAdaptors/RigTargets.cs.meta create mode 100644 KFAttached/RigAdaptors/Utils.meta create mode 100644 KFAttached/RigAdaptors/Utils/InventorySlotGurad.cs create mode 100644 KFAttached/RigAdaptors/Utils/InventorySlotGurad.cs.meta create mode 100644 KFAttached/RigAdaptors/Utils/KFExtensions.cs create mode 100644 KFAttached/RigAdaptors/Utils/KFExtensions.cs.meta create mode 100644 KFAttached/RigAdaptors/Utils/QuaternionUtil.cs create mode 100644 KFAttached/RigAdaptors/Utils/QuaternionUtil.cs.meta create mode 100644 KFCommonUtilityLib.csproj create mode 100644 KFCommonUtilityLib.dll create mode 100644 KFCommonUtilityLib.pdb create mode 100644 ModInfo.xml create mode 100644 ModSettings.xml create mode 100644 Properties/AssemblyInfo.cs create mode 100644 README.md create mode 100644 Resources/PIPScope.unity3d create mode 100644 Scripts/Attributes/ActionDataTargetAttribute.cs create mode 100644 Scripts/Attributes/MethodTargetAttribute.cs create mode 100644 Scripts/Attributes/PatchTargetAttribute.cs create mode 100644 Scripts/Attributes/TypeTargetExtensionAttribute.cs create mode 100644 Scripts/ConsoleCmd/ConsoleCmdCalibrateWeapon.cs create mode 100644 Scripts/ConsoleCmd/ConsoleCmdListParticleScripts.cs create mode 100644 Scripts/ConsoleCmd/ConsoleCmdMultiActionItemValueDebug.cs create mode 100644 Scripts/ConsoleCmd/ConsoleCmdPlayerDebugInfo.cs create mode 100644 Scripts/ConsoleCmd/ConsoleCmdPrintLocalCache.cs create mode 100644 Scripts/ConsoleCmd/ConsoleCmdReloadLog.cs create mode 100644 Scripts/FbxExporter07.cs create mode 100644 Scripts/Global/CustomEnums.cs create mode 100644 Scripts/Input/PlayerActionKFLib.cs create mode 100644 Scripts/Input/PlayerActionToggleFireMode.cs create mode 100644 Scripts/Input/PlayerActionToggleMode.cs create mode 100644 Scripts/Items/ItemActionAltMode.cs create mode 100644 Scripts/Items/ItemActionHoldOpen.cs create mode 100644 Scripts/Items/ItemActionRampUp.cs create mode 100644 Scripts/Items/ItemActionRechargeable.cs create mode 100644 Scripts/Items/Modular/ActionModuleAlternative.cs create mode 100644 Scripts/Items/Modular/ActionModuleAnimationLocked.cs create mode 100644 Scripts/Items/Modular/ActionModuleCustomAnimationDelay.cs create mode 100644 Scripts/Items/Modular/ActionModuleDisplayAsBuff.cs create mode 100644 Scripts/Items/Modular/ActionModuleDynamicGraze.cs create mode 100644 Scripts/Items/Modular/ActionModuleDynamicMuzzleFlash.cs create mode 100644 Scripts/Items/Modular/ActionModuleDynamicSensitivity.cs create mode 100644 Scripts/Items/Modular/ActionModuleErgoAffected.cs create mode 100644 Scripts/Items/Modular/ActionModuleFireModeSelector.cs create mode 100644 Scripts/Items/Modular/ActionModuleHoldOpen.cs create mode 100644 Scripts/Items/Modular/ActionModuleInspectable.cs create mode 100644 Scripts/Items/Modular/ActionModuleInterruptReload.cs create mode 100644 Scripts/Items/Modular/ActionModuleInvariableRPM.cs create mode 100644 Scripts/Items/Modular/ActionModuleLocalPassiveCache.cs create mode 100644 Scripts/Items/Modular/ActionModuleMetaConsumer.cs create mode 100644 Scripts/Items/Modular/ActionModuleMetaRecharger.cs create mode 100644 Scripts/Items/Modular/ActionModuleMultiActionFix.cs create mode 100644 Scripts/Items/Modular/ActionModuleMultiBarrel.cs create mode 100644 Scripts/Items/Modular/ActionModuleRampUp.cs create mode 100644 Scripts/Items/Modular/ActionModuleTagged.cs create mode 100644 Scripts/Items/Modular/ActionModuleTranspilerTest.cs create mode 100644 Scripts/Items/Modular/ActionModuleVariableZoom.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleAlternative.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleAnimationLocked.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleCustomAnimationDelay.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleDisplayAsBuff.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleDynamicGraze.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleDynamicMuzzleFlash.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleDynamicSensitivity.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleErgoAffected.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleFireModeSelector.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleHoldOpen.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleInspectable.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleInterruptReload.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleInvariableRPM.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleLocalPassiveCache.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleMetaConsumer.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleMetaRecharger.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleMultiActionFix.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleMultiBarrel.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleProceduralAiming.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleRampUp.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleTagged.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleTranspilerTest.cs create mode 100644 Scripts/Items/ModularActions/ActionModuleVariableZoom.cs create mode 100644 Scripts/Items/ModularClasses/ItemModuleSortable.cs create mode 100644 Scripts/Items/ModularClasses/ItemModuleVariableZoom.cs create mode 100644 Scripts/MinEventActions/MinEventActionAddBuffToTargetAndSelf.cs create mode 100644 Scripts/MinEventActions/MinEventActionAddItemToInventory.cs create mode 100644 Scripts/MinEventActions/MinEventActionAddRoundsToInventory.cs create mode 100644 Scripts/MinEventActions/MinEventActionAddRoundsToMagazine.cs create mode 100644 Scripts/MinEventActions/MinEventActionAmmoAccessBase.cs create mode 100644 Scripts/MinEventActions/MinEventActionAttachPrefabToEntitySync.cs create mode 100644 Scripts/MinEventActions/MinEventActionBroadcastPlaySoundLocal.cs create mode 100644 Scripts/MinEventActions/MinEventActionCVarExpression.cs create mode 100644 Scripts/MinEventActions/MinEventActionDecreaseProgressionLevelAndRefundSP.cs create mode 100644 Scripts/MinEventActions/MinEventActionItemAccessBase.cs create mode 100644 Scripts/MinEventActions/MinEventActionItemCountRandomBase.cs create mode 100644 Scripts/MinEventActions/MinEventActionModifyCVarWithLocalCache.cs create mode 100644 Scripts/MinEventActions/MinEventActionModifyCVarWithSelfRef.cs create mode 100644 Scripts/MinEventActions/MinEventActionOverrideZoomFOV.cs create mode 100644 Scripts/MinEventActions/MinEventActionRemoteHoldingBase.cs create mode 100644 Scripts/MinEventActions/MinEventActionRemoveItemFromInventory.cs create mode 100644 Scripts/MinEventActions/MinEventActionRemovePrefabFromHeldItem.cs create mode 100644 Scripts/MinEventActions/MinEventActionRemoveRoundsFromInventory.cs create mode 100644 Scripts/MinEventActions/MinEventActionSetAmmoOnWeaponLabel.cs create mode 100644 Scripts/MinEventActions/MinEventActionSetMetadataOnWeaponLabel.cs create mode 100644 Scripts/MinEventActions/MinEventActionSetPassiveOnWeaponLabel.cs create mode 100644 Scripts/MinEventActions/MinEventActionSetStringOnWeaponLabel.cs create mode 100644 Scripts/MinEventActions/MinEventActionSetWeaponLabelColor.cs create mode 100644 Scripts/MinEventActions/MinEventActionUpdateLocalCache.cs create mode 100644 Scripts/NetPackages/NetPackageEntityActionIndex.cs create mode 100644 Scripts/NetPackages/NetPackageEntitySpawnWithCVar.cs create mode 100644 Scripts/NetPackages/NetPackageFixedReload.cs create mode 100644 Scripts/NetPackages/NetPackageRemoteAttachPrefab.cs create mode 100644 Scripts/NetPackages/NetPackageSyncWeaponLabelColor.cs create mode 100644 Scripts/NetPackages/NetPackageSyncWeaponLabelText.cs create mode 100644 Scripts/Requirements/ActionHasTags.cs create mode 100644 Scripts/Requirements/ActionIndexIs.cs create mode 100644 Scripts/Requirements/AmmoIndexIs.cs create mode 100644 Scripts/Requirements/FireModeIs.cs create mode 100644 Scripts/Requirements/HoldingActionIndexIs.cs create mode 100644 Scripts/Requirements/HoldingAmmoIndexIs.cs create mode 100644 Scripts/Requirements/HoldingFireModeIs.cs create mode 100644 Scripts/Requirements/IsActionUnlocked.cs create mode 100644 Scripts/Requirements/IsHoldingItemModificationActivated.cs create mode 100644 Scripts/Requirements/IsInJeep.cs create mode 100644 Scripts/Requirements/IsLocal.cs create mode 100644 Scripts/Requirements/IsModificationActivated.cs create mode 100644 Scripts/Requirements/ItemActionIndexIs.cs create mode 100644 Scripts/Requirements/ItemInInventory.cs create mode 100644 Scripts/Requirements/PercentInHoldingItem.cs create mode 100644 Scripts/Requirements/PercentInMagazine.cs create mode 100644 Scripts/Requirements/RoundsInHoldingItem.cs create mode 100644 Scripts/Requirements/RoundsInInventory.cs create mode 100644 Scripts/Requirements/RoundsInMagazineBase.cs create mode 100644 Scripts/StaticManagers/AnimationRiggingManager.cs create mode 100644 Scripts/StaticManagers/BackgroundInventoryUpdateManager.cs create mode 100644 Scripts/StaticManagers/CustomEffectEnumManager.cs create mode 100644 Scripts/StaticManagers/DelayLoadModuleManager.cs create mode 100644 Scripts/StaticManagers/ItemActionModuleManager.cs create mode 100644 Scripts/StaticManagers/LocalItemTagsManager.cs create mode 100644 Scripts/StaticManagers/MultiActionManager.cs create mode 100644 Scripts/StaticManagers/RecoilManager.cs create mode 100644 Scripts/Utilities/EasingFunctions.cs create mode 100644 Scripts/Utilities/EntityInventoryExtension.cs create mode 100644 Scripts/Utilities/ExpressionParser/ExpressionParser.cs create mode 100644 Scripts/Utilities/ExpressionParser/FloatExpressionParser.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/CommentParser.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/IComment.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/ICommentedOfT.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/IInput.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/IPositionAware.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/IResultOfT.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/ITextSpanOfT.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/Input.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/Option.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/Parse.Commented.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/Parse.Optional.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/Parse.Positioned.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/Parse.Primitives.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/Parse.Sequence.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/Parse.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/ParseException.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/ParserOfT.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/Position.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/Result.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/ResultHelper.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/StringExtensions.cs create mode 100644 Scripts/Utilities/ExpressionParser/Sprache/licence.txt create mode 100644 Scripts/Utilities/Modular/IModuleProcessor.cs create mode 100644 Scripts/Utilities/Modular/ItemActionDataModuleProcessor.cs create mode 100644 Scripts/Utilities/Modular/ItemActionModuleManager.cs create mode 100644 Scripts/Utilities/Modular/ItemActionModuleProcessor.cs create mode 100644 Scripts/Utilities/Modular/ItemClassModuleManager.cs create mode 100644 Scripts/Utilities/Modular/ItemClassModuleProcessor.cs create mode 100644 Scripts/Utilities/Modular/ModuleManagers.cs create mode 100644 Scripts/Utilities/Modular/ModuleManipulator.cs create mode 100644 Scripts/Utilities/Modular/ModuleUtils.cs create mode 100644 Scripts/Utilities/MonoCecilExtensions.cs create mode 100644 Scripts/Utilities/MultiActionProjectileRewrites.cs create mode 100644 Scripts/Utilities/MultiActionUtils.cs create mode 100644 Scripts/Utilities/SaveTextureToFileUtility.cs create mode 100644 Scripts/Utilities/TemporaryMuzzleFlash.cs create mode 100644 Scripts/Utilities/TypeBasedUID.cs create mode 100644 TreeCollections.dll create mode 100644 closerex Closer_ex-7D2D-mods main 0-KFCommonUtilityLib.zip diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f6a2d21 --- /dev/null +++ b/.gitignore @@ -0,0 +1,80 @@ +# Build and Object Folders +bin/ +obj/ + +# Nuget packages directory +packages/ + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates + +# Build results +[Dd]ebug/ +[Rr]elease/ +x64/ +*_i.c +*_p.c +*.ilk +*.obj +*.pch +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.log +*.vspscc +*.vssscc +.builds + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper* + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help +UpgradeLog*.XML + +# Lightswitch +_Pvt_Extensions +GeneratedArtifacts +*.xap +ModelManifest.xml + +#Backup file +*.bak + +#zzzili +v15/ +AssemblyOutput/ +AssemblyOutput/** diff --git a/Config/Localization.txt b/Config/Localization.txt new file mode 100644 index 0000000..d18bee6 --- /dev/null +++ b/Config/Localization.txt @@ -0,0 +1,31 @@ +Key,File,Type,UsedInMainMenu,english,schinese +inpGrpMultiActionName,UI,Controls Dialog,x,Multi Action,武器模式 +inpActToggleWeaponModeName,UI,Controls Dialog,x,Toggle Weapon Mode,切换武器模式 +inpActToggleWeaponModeDesc,UI,Controls Dialog,x,"For weapons with multiple modes, cycle between them with this key",使用有多种模式的武器时,在不同模式间循环切换 +inpGrpFireModeName,UI,Controls Dialog,x,Firing Mode,射击模式 +inpActToggleFireModeName,UI,Controls Dialog,x,Toggle Firing Mode,切换射击模式 +inpActToggleFireModeDesc,UI,Controls Dialog,x,"For weapons with multiple firing modes, cycle between them with this key",使用有多种射击模式的武器时,在不同模式间循环切换 +ttCurrentFiringMode,UI,Controls Dialog,x,"Firing Mode: {0}","射击模式:{0}" +ttFiringModeSemiAuto,UI,Controls Dialog,x,Single,半自动 +ttFiringModeBurst2,UI,Controls Dialog,x,2-round Burst,两连发 +ttFiringModeBurst3,UI,Controls Dialog,x,3-round Burst,三连发 +ttFiringModeFullAuto,UI,Controls Dialog,x,Full-Auto,全自动 +ttFiringModePumpAction,UI,Controls Dialog,x,Pump Action,泵动 +kflibTabRecoilSettingsName,UI,Menu,x,Recoil Settings,后坐力设置 +kflibSettingRecoilCSMName,UI,Menu,x,Sensitivity Multiplier,灵敏度倍率 +kflibSettingRecoilCSMDesc,UI,Menu,x,How much sensitivity compensation should be applied when dragging your mouse against the recoil while aiming. Easier recoil control for low zoom sensitivity users.,指示在瞄准状态下抵消后坐力时要应用多少灵敏度补正。帮助低瞄准灵敏度的用户更好地控制后坐力。 +kflibSettingEnablePreRecoilCompensationName,UI,Menu,x,Enable Pre-Recoil Compensation,启用后坐力提前补偿 +kflibSettingEnablePreRecoilCompensationDesc,UI,Menu,x,Allow mouse movement to negate incoming recoil before it takes effect.,允许在后坐力生效之前使用鼠标移动将其抵消。 +kflibCategoryRecoilCappingName,UI,Menu,x,Recoil Cap Settings,后坐力上限设置 +kflibSettingEnableCapName,UI,Menu,x,Enable Recoil Cap,启用后坐力上限 +kflibSettingEnableCapDesc,UI,Menu,x,Allow capping vertical recoil at certain angle threshold.,允许使用垂直后坐力角度上限。 +kflibSettingRecoilRemainName,UI,Menu,x,Recoil Multiplier,过量后坐力倍率 +kflibSettingRecoilRemainDesc,UI,Menu,x,Recoil multiplier after reaching the cap.,达到后坐力上限后的后坐力倍率。 +kflibSettingEnableSoftCapName,UI,Menu,x,Enable Soft Cap,启用平滑后坐力过渡 +kflibSettingEnableSoftCapDesc,UI,Menu,x,"Lerp towards recoil multiplier before reaching cap, resulting in a much smoother recoil pattern.",在达到上限之前就开始逐步降低后坐力,使后坐力表现更加平滑。 +kflibSettingMaxRecoilAngleName,UI,Menu,x,Max Recoil Angle,后坐力角度上限 +kflibSettingMaxRecoilAngleDesc,UI,Menu,x,A fixed max angle to trigger recoil cap. Only works when dynamic recoil is off.,设置固定角度的上限。仅在动态上限禁用时生效。 +kflibSettingEnableDynamicCapName,UI,Menu,x,Enable Dynamic Recoil Cap,启用动态上限 +kflibSettingEnableDynamicCapDesc,UI,Menu,x,Trigger recoil cap after certain shots.,设置基于射击次数的上限。 +kflibSettingMaxDynamicRecoilCapShotsName,UI,Menu,x,Max Shots Before Capping,最大射击次数 +kflibSettingMaxDynamicRecoilCapShotsDesc,UI,Menu,x,"Trigger recoil cap after certain shots. This is a rough value, and the actual cap angle is calculated by the max random kick angle per shot.",在射击指定次数后触发后坐力上限。上限角度是根据最大随机角度计算的,所以实际射击次数不一定与设置完全一致。 \ No newline at end of file diff --git a/Config/buffs.xml b/Config/buffs.xml new file mode 100644 index 0000000..de1765c --- /dev/null +++ b/Config/buffs.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CustomPlayerActionManager.dll b/CustomPlayerActionManager.dll new file mode 100644 index 0000000000000000000000000000000000000000..3ac6ad7739f85604ecbb9571f8b24e44094db215 GIT binary patch literal 18432 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 literal 0 HcmV?d00001 diff --git a/CustomPlayerActionManager.pdb b/CustomPlayerActionManager.pdb new file mode 100644 index 0000000000000000000000000000000000000000..91854ea19203a1832e5f68e1287e1e68a14d99e7 GIT binary patch literal 11832 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 literal 0 HcmV?d00001 diff --git a/DOTween.Modules.dll b/DOTween.Modules.dll new file mode 100644 index 0000000000000000000000000000000000000000..dbf31d28a7de739f7f44d9306c13d09f70ce2e42 GIT binary patch literal 43520 zcmeHw3w)Ht)%VP^_su3`Hz5fm!2p6Qfk?P13PMP@1i1tfuA;Cc3#=yDWOoC^5SxfM zyyKl#E#6)))mm?@T5VBltF5-u)>evItol`2ZEIWKYTFmT|2Z?yv(Ih2Eft$4>f?op;<*dEznODCYi%Uqq_( zfBLRj65+3KpAbulI3&bAU5?oFpA-Qw$A4RhrnK-MQx!sZZCYON3v7H z3S89IEc*~|s7fRg&B)@q9RfiOy$hG^Z?+J#s}j-HI25U_LTDe{%Z!!G7GjRYXkx)W zMNr)g;SzOg;EE_CXpMjERxr^i)}jb%5KOk9`}}UB7wvL7MiI~yAK&t2~uSNT?+188(gai=X9CXB4rIX%5a2-pt9qLz@YPw8)1Zl zbRTP=9U(0#(Dy=pAFA&~bf0DvlSjTCE+%f2Q5-JO*~9dGINhoJb5UI%V0vI3~uM2Rarl5LRsKpUu7FxjbXc$JMr+6GB%HW*!vAiIs>rVUabXakmm$)vX7 zQ#LT?Oy7_s+lDe^w=u%BLF#rJPH_g>4a>n~m$u7%Om=Jgn1?hUFp{0F;*%W3`3^Tb zsuwfUNo3!*dok{v?xNm2x`nF<5);7bMzznQYOCQ$K-n&LG8DT!&*>^zd+wP$Mu+Dq z$CrgM94o^ZFO|qF4x>{m0op^LlVB!{9;oaMk*yxKc*MQqs0Q6Ts0}?+P>!wIO|#V! zZM9fgoeD)5>pd!98bw1-LkZm$1{{$IcrpR@P;JACB#(sA*_G#?f~+vyUO84N!0!20 zBhjxUrv}m(@dylS0bwxt1?W(WMNo0(sorsg5gDo8ed&5rw$1Y{N1iLsojeVC&M@jw z>Fyy7ifNT4VRRyf&gsZ3?wy5H(Rt3^*KW{+^w% zr{a^4uOc4S6hu6>bHsgv&CHFa8TSsVbk7;4MQxBr0mV78Wsh?`1gXOkwR&J!Vw*?Y zH(51-b15uQEyk&}<7V^)W_&OSg2xb+Ju5Cau8QS&uEe01fuh{XVz1BPyAvHC!;4Ur zyGZUUUY+anOnT1@7<f^^zM?{!l@=Lmo zWB;u>VzyI3HQUEf1x{5Jy~S4PTaQs`D*ew?I&1oK{8@oEAXWvFx9K)u`(Rbz%eD&a zH7j6+IM%d>xU`q75NE|WM6qDJSQL+29x(_oJxgruMOuu8_qI? zLs~W*mw=8ySPSwL_dDXtp_k*iDu%&)N+0q(zB@4!WP#H+p*-m9X+$v#aE$pcr_9{f^luL zlH?lX^^R8_`-;tD57<0Lo~H*LY$FJiy{7iEm=Xe0Jed5dwq2!=9-`6+A2hMQMl@zW z^|~I5Q?oIK9@Og zCVJ>|nFE-h|KuESirHu|S{+R8)Bc&F{QNAnxfV5oFPX?*l>QDjbmw>07Pg8D zSR{hUUu*0dh5bI^=`nhkX!{s7#}?^kVPT;NCV!)`<|wS++OR%28W!o=uxJiqu?QwV z)L5tswfT28tlwv2xqC<}WA4zn#9|Rl{z2o^DV&dNIDfQoRF^E^?w&^@sia6ha#1l| zJ!`yUaR?^=q;cUNs^6b&xF4Iix;t#R!%bW&X2(VM2!z{U@;@~$szJDavEhDV;$pmW zEzSNQUCW1VF&|h6x54D68Vdr#`YV;!bLVeF^W5Qw5T`588D58$yL(7ET!7h!N2RkM zq5X_cECwdRZZP?GjfqAP=6~5Rk64%lSDfe0^Muc4Oj2gdl5n9Nnf7U3fjBA4OUS3>!IWz28=~9J6YAJetFiRCzdJ zVW8(3!os``CIcD^9Zp!eR6d6~@Q6E)=m2QF7j}g=P(}}_W@DX3SVJ_{a)p&|!wMb+ zi&X7cvr#XsJHcc~V>K$Q0vlFg78Z_?RK-ZwnsaJ@J(IA8YOE%ORYc|CZE9mN(db0m zGaG4T>>Z-06Z{oSmS~)ngoCH}RdjdsuArN{hq&>%d9E=Nd}G5AKvv4a-qnQ&%qkFi2DCT162_{Rm%{27OJaEYfu@<#kP0^SS}YFvW)-~OrD@^Z&0@B_D|YI*d*JC zj8?l(9Nad6+H51z3ap926&j^w<5q_E&0SXfB;@GGq=2odyIa4zzk*##9G2o;_xtqL0lFF;(&#L`N9|&$BcoANEk{S#_XVa5NE@{dLtIvFfalc z16_r?qZhrySQx201Sy*S-u+Un@>gKzn_dLE2?cK)r9V$Cqrm%>!VUdrq z=d;?@%Vmt-^EJi}g`vdZa)m*h!nojktZ~lqa$IpA5rs$GXHd_gCjKz0;U9N#xCgg5 zVEkiWt)b5VP}raN7M8;>Z1~60s}o-UF>aEo5(Lv|sw0{p8Jx(YXJuajn5x)?6I4oUm7dzq?k<@O%O%^V;W1?oB!GzwygucOq zeiB}ig_$#$5L-fR{cOYNvACW~QJ6o5CqG%@Or~I>TTl$f!j87*0cpZ?qnJOc2NvSH zGrkKj6ABIW@i<``J-Lvtsm!s-_%nW+6+ea`>5f@43h2V<8G<4Pf4W^9z6=><;meV( zUa88s;}~igomN1mvt3$9!YfGghX#L)Z1k|`N{9->S0SBHU=umwS3^`O9RtwO-2>6F z1gFtUz!*I&%0#zBM@L6UaK^8pYT8C2=J-G%ChI^UT;YuG&MJ;+q%|?liE+fQB^By& zE3fA|hWt(|A|9FHvaAY+bOs3eX-l+n&Hq|Bq@R|bFVrbU_k z##$t@`fU(2m_A{EX_6epbl7hCL@-7Vi!x1HqGOpxL&g!>Dslxnj2H)hC}bZ+m39?k zvQ$PGJ>wz8^Ql9Cp!XMp4khEAzTa^02Q~(O7&C^gxx+V5AKy9zM_RVI_low_c>IO2EN>yj|&?*_zRGDE{A!eY;Oj7x}Hbjgg{*5d{r`uJC8K^SLu0qT}mDzR`Vg{;Um*tENBo;vDz&8Yv{oU;5q~C21%W=TLd-ywxpoy|2CB>>m2YW7#5m&L zwi`kipHC{(jn)c65*@}fIuyzXPFcz%If`=q0A-R4ri@{`&{U?;M2sE>v}{{>YS}&m zxwLFs;;bTgHgSu7gy3boS6c*iUbl$=+7jHXbsJ&dT(=39*KJGIyO>I(?a-1<8wYEz zrt%3eybtp9R*kCW&YTX2I#?^5@n@l^$>%^?QHL`19Dm+Y(R2Je5ZD7U8m54#<-|DR zRK~8doK(mFsSx9cXQMQd$_rYB7)SiOStw1UVup2MvZ5_k(G`%6`zuyUA`CteH26qy zLawocWZ~}tw6aJsi5Ky3V)U#gIY@u}r7VkUkYiaSCd(rFeJ!bcpURW+!Ceh?gzSvbTPJsXf7 z9S3cXK*0*S#AJm_YydYhQZp(3fLgP}E^@?Qwzm-KEvz0T^;fidTI7iTkYt!krPwFE ziaUl9o_{t$-R~a1&gj`f1rt!3kTB0gl#tJX-nkxN1b$2hd}UA1&t4kJ(9vfbh9~#idYUxo8P0` z%ZLnRZ*N+f)!yAVTkVYlIHSE7Ji5J@0J^;?Py^aaLe*X@AIEGj0inHH>9!+@6wem) z9gxbm;zkci(O$aQ+Dk>O_FCr0!NU$z4&!!NH|e%XO6 zH5bkYHDGLzQ2FH_#YzH#U%o)M9lc0tY>cL{fmlgWIE8LDr%(~gDVBMPmCSIkFk>ad zGp@byX{lvIE<4!fg2dN(%y`;tK>TLLl z{)`@Ut}cjJ#tc_)lx9>1k~}k(9WllgXF!t*Z4WOn@oZ*EMvr(q&Ajo2ieXHn=R(Mj zI03iPswt@&&R)tH_kE-1BCF(R&8Uiz+^U$-b1~Q~AkqL3<&1-$F2UXM6EoD@Y(G)P zxXX;5S;!k7a`e1`dnylWlr#P&$Z;-b{4KgqGvdc%Bou}ZX>LrKITnc?&rg$LDgtfx|BB-fWw%BMgf3^>gynT8vOA? zkT<6_zLAviXTXQ6j=Lkr=LhpwIhhW&$@+R+>u|yGVhIHI;c|mUMd>pJ@m*Z-Bg;rm zR{&QC7nS$oqI|d)e>dRcfBJKa+Ta5vZn2Wnt(^WQzrUnFyj()L=a)WP;1>)1zaHWj zQ-(h{EKh96Z61;*zFYkLBDeTa{sSc;5%V`AcPw&?#Czqz5* zkY9YItS;mhxB3We6-#~<3g-L8N38Sm5Yo95avUU;P}z}%L?0+1w9kCaLxzj7IV2wj zDQzT{i3X^sH{6DBwhoiU;F^J zMu}u8$&V}U&hd*OKz5676&)$`i=T6?l3dT1hMf(I-KAvf0|9Gmdp9@4Lr&_%$#3zF*h4ia~Qstw~e`*mZz<(ihGz-_Qs3*#RcRg#NJ_|N<3&Q zS0%n`D|eE3m^oGJiQ+LEO11a~bE?*p#8b?vT2B_wFsJG{MeJiv)pM$No;l^gX^3%D zPvyar#Y@ax!Tvl&yv*FE%uN?RVy=Pv?^N+)=I&wcH1Qg9N0^%-UT1Cv_uou$khuq# zJ6*iRoP+ysmUx@Fwam?ix2P^t*>N{y+QbxdxE)TBETHp zzd>D=iy_SIV6IVwnEMHHO=2i>6UhD)93rF`2n%5uo129G=SDw|vC4i<6o2 zAojd15@I@Yoy={+Y$i`U$=nVxQyTcrMR7l7W({+XBaZFI=cl#I z{U88>fQTE~B1&~)1e$m2NJ?u7%zNeJ%GbML$?%?Us zt^5Z{nO3N*iJ8X9l-$o&DE(W}MGk7al6;lrkJ{2Fn6{_Su*9A|#}a$`J(m3UrpNZi zJ*6*m9qj3Tmi!FqCFKV#dQJ)T+Ji-JS(1B7NyqdIdBdd14<=1I_mrwOz5}{FM`5Pv z-T5S0T>L)Li^{)xh1|Lv0HPE&@2{T*4!@x zCB71IujbwdH%xp@a~oh`xOhTyIiaz>QV|%XYJE@6bl-8JLvud`H(LBua|MCvz7xbL zqm|~R`Dgel#Wk8+S-ReLlE^<^<++NxeN)6^yj{Ohd^2>h?^H2mtjc>1T#a~{x$BU3 zmv4cXasuUDC!PbhNIb^ejUp%Xgs(w(!>ZgpIY00%zv){i0w*d> zSMdkF^K&?aizaU9MW8C z?o9vrB0NE1jwo5;?-z$Occ6HU|3a~@O69fYw)ig*cWG{aams(0_`u4$#DArja+1>A zU%bbEjo6{N*4zjD*NN|F?zd&%^4}=NPc-fQ(7#8#tGQ93U-)kk6RTBTHMqTEhvq`y z?h-F*Zh!Ib{P&9dNoLJt&R4{0%~j}hrg2Zi74aeUd+_t2Xl^yEt>gb(U@ zeelmYe!1vWWnq7@E08Cz*WA6uC4r#yo~H6zbE^WyvO#n0<+B6B%_71Eb{=7S|paE2qpBVG&iDTci<#hce=_OQF3cwlKh+I&K-JxV45t& z83y_D?}7URr^wSZ_jtkmfm7v~n)}b;j|OJQ9h%!x^h{uuyj64a%I^=%k^40F)za?; z>f|Z273OK7?*$gfuW4@6(1U?R^3R(4OWzmH?&6Zwc)z|$-oe~XaiP=WX_60_ zoadm?B%iTqu8=S2yc1j=&kFft&Eo90USzRrudJ)V`)UrROHDW>@j8Y|^- z%qi=u*+?2NokIvA4*JH=GSyd)#ND63`F z+;m;m$Z5>&6t6nxdDh6l$lgU&mS%e7_Xb?LlEF|yXk3o`O9(|Ma* zgn5(Z7J9cDYvkRUd&4KiTKSCTPVmq3td-x_+?D>V##;Hh=6($Co+&%#rCW5S+|Hcx z?wRs3%?(4_&y=^?G}pHhQ%5(=TO8{pz1KjPo4vch?XqcZkh^u>h0a?X8{};! z=h+4B0h?w-KBn__12ZC@)?61bBl6G8-6&ou_%yIlzP5nusam(lH=Gs1)_8o>c3o%+(y#Ix0(^pD>cokuPiR z=bo*`Ir0xS&2!}^I?s!-d#)V1Pyxp)Kmv5RJtjFbVZJHhO zPde}KXij^ne zbEiQwA)9QPNx4qvJ&ZV?lrha6bYCx$a+^&vCBLBaUVvswUZJ_)Lo+46Xw&SHcj!Dn z)_^YgkmkmEt`}YM8Jp%-`GU?{3eBzZ$C^6}np@=|o8~t8zRr8dJMUi8=na*pP%K#yG@H`z3I%66Ui26jO^CB2qK@p>P2K|AFxo92abx6b<( zG%u95Y3>eaUML^1Xb#`OnR|&ema2NL^18$&vW7Vor7o5AI*%gCrE;aoA);I=TWp%UWUJ1*!+o=7 zm+aQuHs4*~F0pA|Ca>0cv;tiwZ`K^GK$po^ZJL+M*KL}Y%R@HJ%VkMJx{t1q70m4v zgn5OepZp=u6Xq3igH7{FxkcxF8RPm&*=2GV*H_A&HqEQ#^@xvaXVk z*fg(}PwBi8jF7A4E1LT|Ft3*HGWWKO;wz%p$XAz9&EA$53@HY8NOP38TmE@@I&Zgh zHY$$tu9fd=st|7^>$L~~T`dMQ?>^RAcqnxniMC>irO6gP5hlBLHu0Je1mgMvyq(hocOEW*;5ID$T9HJk|HxW$azZK=@JH)qf z-m4`4YMQQFe!f$j88UJHd*r{%P2=BHqI^PjpDN4GcZss%bguH)(~vmD`#9-#!6*6o z?u;7#8nq>_62fak2;qTT()luc;t{{Gq5XTB57=sJN3hGyp8dSM_y4X3vTJT1?K{f; z@%T4Ac`TgIOXukI`S0pSyEl&BiqFgX|7|$`UY};SVvlXU{~mMPC43{YV**73hge%c zWtGm%Ql&#N;jHrfe6RSWZC+Eq{44sZ?~Wap%>K=;|K}}Fd-W+^UkIPp4)V;L5^D7V zYrROv^K>bDeYORtR3FFBldxu)>x-%LuSsr4>~)BPi1228t}V{)seyA)NzTJNN#+W8 z5!N+B)Z;TziO+A2Mf*`_M~3FEqHKx6v9HMOIcZx*lapO#-JTlwM9P#K`25MFrT9AQ zf4=F91=RMxv6ask`Tt$CYq4L#KJ}RC3B2RVPR+g}x!HG0X9IQ`29Gp+M;ra<#OKOn zg~ok#LmUz~#W2DCq+_op7nZ4mF_J2UU${e}1N4%>V9w;JBVZ`r?x-%+O% z?jTYZK8+`OBvQXv!}P;)bxFQ>iTCU;@m~ESNTm3b(*ShF;T;`HM;iARoh(i?ZY^y9 zeP4b%(x(e36~!r}pB8l^-I7oAbLEuYSVC!0E~P8V`;a?*AW_8IMOuvI~c~Wkt_<3QjoMLH~${FIlVasH{xH)%)tTrCcJsb2> zWieSNz7tF#y(PF^Mns^v7xJ>=3*<;+Rqo~TM57`98l-;?ehKN=(mUlcgYZu@rk6hi z{jZll1^MfNXF%^9LG+gjpF!DshWr3@d;UXmjd4}!FXVlw$@`GsU-Sv&+wxB_7IA$Z z7VnfVF&-Ab%Uxzjd4lP08Hdr*gOE^7 z-WE&Beh-A>bCwt_T&mS7JJK=IC=D!kNV%Z&e1}gi81j_#$r&XVIX)GqlsaAq%+dEF0{i*b$HM@(g^2$m(xG8WW1|WPR?(1 zrP$&Q%kE}Zzfn7457LIvt*#4Meub6$h>Or(c2!HVy9>Vhge5`u9=5pK*k3#b^w5%1 z+(gfE@5f7+DcNs)TF?l2`-t`Kexq?ji~F$b&+kIIxV#5xXTdIr01tmWgvp zi#(lTdr=wEcMC^)BBCFCyntQe5CF4JWm7W7)8FUVay=7~S{YK%4si0pf zo8>u-vh$F>Tj)W05&HCPMxg#W!}F5pg}3YFMWs>CZrM=aLAnB(yJc+|rDuaaz}62K zua}+cc^mp&o&(11dFOlT<*uRgASr-km>eDOAe|66XiS%%pzL(%DL-h`$Ph4Vq=ckK z9$!F`!ZJ#yvHS#<*Rp&n%RhhzYUF`ZNKuR8#mjr$UdOd!ss?)e9{~ga^ zd2P{Qq%lYib7b2uM&+i^zuSvEo=&5<^i$969Od>S&W`qWijNRm4sa@s>&nJ@_Zt=H z>)pmTLkqmSjpvXW_(j4f(&?PmbK1@6E>8DwdLL4+coLspc=7(-W^YKmg494PCi%xK z|5UVs{x8vqTq#L2$mvi?@?nzX+`+WrdX?&sXsIQIbOzKL8ze9RJ; zlj<;((=nV*<#dJfBKT^JlQg?Pdqp?skmzN}s~o z%k-U0?_>ITrVlaw4%5OQOou@@6-3vK;&-5Xt-(ecxZK3)*8K3FVOwVSz zmgx;lH#6PG^j=QyWXV3JpJ)0I)9)}XT#W2uWTrA1?)56X8ZpLSNG}E)0u4Q@y)6GoxF};)Ny-eT9^ggDaXZjG+?=USqjPGH5 zrbjb9o9SAnH!$7IbRW|@ncmCvolNgz`gx`gG5rqH!przx#%Fpo)3cebWqJeC%}n<( zy_4y^Oy9}$KBk{%`ViCaFfDwH?_+$XM>9Q}=~|{YFx|{_AJaRT-pllzOz&g*d8Q9B z{SMRk#wm>)KjSk!n(5h0*D}3<>1L+;nBK|sUZ(G4dLPq=I2AdBS;6USPB(Dcmor)P z_cFZ?v@dTT(}zGW$~(lg2uv0?<%s~JfqpBmg6Y|TM&NJYv~TPgp!abq zP9S>yYbzxju0H(Y3}MbI09R zyT9bV$Ni}L+wL6CSkH3LD$kXkuY0C>SK^su6`ogC<4I%IWa69`@?To)q`Sc(yTIbyqAP&dsw!e??1eX05z%ya?-^Y2`67_ASZ0UCf(L2Pl zOuOAUIl#BB;3@J}09P)0ArIFOT=}?yxbVAa_%~b}cye>#-}#{5{c?z6TqWo&`o_m_ zT&1|maFyd4f$KP26}U#CH%H+bjq7;y>KI&Oah-rGjO#>P<8W2t8jouNt}0w7;hKo6 z8rLLTlW|SKH5J!1Tqol?1=n<3r{X#d*9=@Uah;B97OvU2YH-cLRg0?**IZolaLvcH z09QS(g}BbZwFuW@Tubo%@1?jJa4o~N99JW*CR{6Ut;9FGR^eKWYYncoxX#42PWaIN zHMsWUnl6{&S`Rvcs~Oj3mVXzr@5-cjRd$O}M!BdodT^DCS&sF%9v9ztl#5blxwy@_ z3|A7m<)Yu!Ej;eui=DV`z;!#W2XQ@#>jn4S@)w@F~1fP99V`Wl-s$!s_ZljSVWDJg9WapwhvGlLj?5sC4q6(m{pQlLv(zR62QZ>0kiW zQwEbx8dN%YQ0bt;>Zyam4l12IsB}E%8J{JUO}U^o{EYG()!95-yH!jix!PSX$H& z+Zs=$SxaMb-I@%LG-s)#MGTT=Ese=_YcoL7Tx0CKXkD~56|wT?MOva3)7TtowQ*Y_ z9nsoYqS+=}9#2J5X_b|c)~+;1t+ucl646c3L?YTkHZAGA*68-w#@1+taB-|XgKvtp z;+w-(nTA-Zc}tp$q|(fyIBMKrmnbIy(JHX8tF6OgYU5q)sc6E+x5m@loYrW2O9a)c zjoZab;)%9ME1J=QuD6P=j3!bsm>)cMK|B#VFW#OyTE5j;7GC3)$hpyh;)X5^x`AS9 z)j;W@c>LU&R2njxn%5eSqyvZ}?h_GPgLgT}$li z*YfDLSbGbvUDa8$g0!<`Jn}PzX;FG^WNPTSktyWi&!Y5f$kfoYfrT04pC#t_SJ~$H zS6t@!XPGtNnHw<1S(-h@S!f&M%%{h=LNdp=;`E4SCS#1VM0bQ5<18`9I5V~}u6aF} znHxC9Sv+7Av-GHAoO6#c#yLM@e6nQV7-#XoG0x%vV_ad_1~m)PgPPgQLCqp-P%~!^ zYGyJ9H6*8Z(P&-L)!IsNU_-U2TRK0QLdamU(IhiAZ)ac{@z9?n>f2M3C(#5jd&FWg zoH0qPj5ep@3FO*m(cIQZM>5)iS=^Ciz{z$fi^+hRESk1OqwP^_ArsLJlSR#(Miw-* zc5RNeL!d07u-y^@SF;z*H0l3lj-_onqMD- z*J5fB6l-G9))rKOyKwGyOpf+QD|Fi;?EviPz#@uVwIonY+v4%m7R}lRj}~EmEsmzP z#HmmN9(V9Kv@McQb)d(eXv@;}<|tPwx@i;U4IYb97zj~rYnG@n+SwJQyqd0-SiCXb zl>lA0l)}7dY)(Yl&}xi2l(jQzTf_1M?{Ju;jRg}OCV~0i*b!}pBY5Ck=7;wUs3OMC8CN) zg)(?6x~op&-ldKvfb?=EmSf3}wMCn{JE99vQ4I`kULxM6CGZyFN<%!>o@$D#MTqG7 z_T{K$qaznRXt7DxJBsD}_yHRJ24lMY>v3b0bOimRQlz0xfc! z;JpA-G*FnJfx-lZa3<>JSMfB#hPH}YEbIamqm#$Zs3LSO%9FBvYa|hiw5MuOD+~kC ztnX+IRg&gVq>JxO@y+NY#Vu`D6{kjPsx}ctOQ5d?KbF4g_3POOkeM@Iq=SHHR%aAc z#1_08I}$O#P=Q!$G%=r+BH*^vr11Mc8@tFtbYs`%%`^(rvH`u3&cdcD8BJ`pDJy_z zVnM8>CEA|Wq|noz#DqzUR5c3y2lcLC_ zEs8``Q^Y3Bk+dF`tTeNgo`=*BWQuwWix_H>if!c)XVH`u!E}dMtueS|>?gt7cao%~ zo|8bS-J^XhiAC|vt0IYZj5CpJk92ep(G*ud!o&?aHyZ7r(KSBt^RH-PFtZHecT-x6W`@+S7#_nV)+9qf;h{kQ?qNX^7#->E1J-G>w zjBGJwaeCHJN7Z8zx5ir7mQeFh=aSEqxLe&)w7Eka)P@2hfKjpf;UI!I@?)AKCu}#B zx{1JYTo-SP=yJ7Pcp`64X^DEaS3yXSWlb(boEOWw$UW`oNm%E)D5vny!E*u4J5kq# zxlTljNziVI0}4s0I=r3|Lp8M+<-Dr-_{}fcR49;m$NI*ujqn(+f!+D$%8ci74V=du>-T6>sC6i9OTaYc%QA8LNP$nwA#cLE8M8-d5V&Y7cVT=5)ncNo~gIsrBnO zYQ|hH%m*W(mZ;?j;L!w>d64kV2+aIw$|MsyOxI$DAcuBmxY1h3XGX$Ym=fX~RJtL) z4Y_K!65Fm7@t}83coIih zN$Ao3dk&%{ZNQTv6<2q2CaPT{wkv9_Z^SYkYmTBEukct{5F)^uD`j1DGq#XP_Hi;9 z#nwAU%BnJEj1>r-Tg)JxG;7tg1-p|LAXZUlTZME8O2t|s%Gy~~&28^$L!Bw$W@PGJ zmKqM$o*}7tc%0V0q)pz4NtkNx!er3fi$US4mhwbN3Kd07PA#}5*MWy{lcoS`(&^x8 zN|wY;iaXq7)Wf^U@nN3Hpynp2AMtAviAc98i|gvuEzLOEf%^wN)Pa1#;K2zwYVkn` z0iAh-13~8D4Fnm-HUgbOf@DTC($7GA&>=AGtWyu(MXxcgCQ{T7Tv|Y?QGO!R0;sR=Fn2Z!qOr|eQaow1Wu#|rZft54UvY*(A18% z6GPyLDMZ$6kKrhQmR#&3QX-PcHkmsdepD2zaNf{@jc5Al5zb4W$uaIG>)e?=V`JN+ z+pv2;2|giFm7tGGln0qw+K#8T1Zrjb_*6;g%mEKD$lHX+eLTS-3~r4sLGJ*NI*IX8 zL?qEVCbkL;=$804Xy`3gWIL-(n3JgGsm4f$Y)|pkt0hayviq2os;T%I1 z)#r$a*9-CKE}}0UL}*(ww-ftNP1m>MFhg+}8_N}lf22ZP)EeL1kceUCg2&EsaV(jn zIIOp}SU36Di|S?3=2@6Hk3Wa*dlDy8_<6?)d?X&hPs^PkQlL9PC-Gke?iKg|eg!^^ zUjzyP7C$%_gWhIvm^4W1@Zo%uh>GptPX$jX72w-|lERNeW|!KA@~!x<0zYCIMcM^a zJZXa>T(S@a2Js3%BDTU#j3rT6Pk_Thh!-n`uMs+3z!9z`cs&7sKWTqy#08)3s^5L; zW4*~qqdyXk3j82%g_K?wlHgGM+oLkn_nNxB=k&->*gZ7V?~?&ng(1sIh{=@!yh<@N zRPG1_f+JO~5(fg_d})lp8x>`Kzce)nWjrMl@z#sC%y0_nEprQpw=95PM8nMpQ0^2D zLj|k3Ce_5{%3w9#&>)~-HU68bHFQ?6I*>1nP~Wb!g5mO`{<{e86nBL~1_A-R4w9h~ ztT!lo1|_p8sndpMvf-K9@J!S2Oc<_FhG#0nkOTs%eL>Fka|M`mxC;!2J2;ns7x=X| zg8k)?)w_oV7o$aRx#6t9D=JR>sBtwis!4efxX`k6iIJXsDan;N`O-mmZ?J!inH}ms z(QpU6X#6t#7jvS~%bf0D|45=@1lNF9kx<)eI4-mzxMoO&QwGl}4_14*4$%|y9WJUg zfaM5-6)n;Sv)oXU1iXF?VYZm@%!&m2r>e%Y)NoVVBV@k`Eey30wVIN3lx)zB?qo-I zYDagPj_wS0nmyd991V%RhgpF;uZ2cqM%Qwl?%FM6td&MJ53CNK#~Dg_sqtyr_#L;I0tFz-Li*Nz^TjKqzJ~(iQMvFp55gW&Gzs4`MV2it`;jv&`-?`;hu6 zU5)D*;$}{7;dC#jcX4_zrw?%YHBKMn^a)O%=5(Lg-|SfyeTUN*IenSaS2_JDr>}F0 zpG1H&4{`b~r|)z60jGc9^v|4rGEyL#(9A~91p8@j!MWASxtQ$%Zy--kGOdAsY=D8^;HoCfkN^Az{kbbmf) z6>?g_X_*W2xbI07HN7fcdhyyB8Kqu-oZE>yAi8<$LVtNtN4NNyM-NbZLE*iAh8C(;J1!soZ z@?kVXK;6>6f@WN(e~nkrDi`cO3kzMSKaz)#9B_CfHOt7$r?t+=3()+lrer3fM6lW? zoHYLsWbwi#Mn??)qd3McD|J$A>Eu`*jOKb=>^}DCOK4lL?Ni>*5li@CNO_cPOB-WNL zN~Q-rdQGOK#RyFgb(sT!mw`}QXhk3x@qXjHbt{KWIkZdCN{8?4NlN^b2+=nS$%}K4 zJT^y4hdVR|7Z$ZV+@|ANhAW1v4ObTeWGC*uPIsv9N=o)naw{dbQ?i?qyD52)l7}g| z!Ek%&{v;)@U~%mGn350iwkQo*n!=$m0lc-!O=0%Lyg&eR&Wn1mdrtIVcM>`=fC-@6 zi_V^k=2s&|WQqa-!*sz+DAll1aPBa{tE}23C|SMQ1Ox=y$Pxsca)ITBA|d%RG##-m z5IhSGRBN>ftaI77W{qeVO$~KnNLV$}BGky<)GiENHc7ezOm>w+dQ_8LY!a{5+U9yM zf&gB)wM(!XVym?*)EnySXR>csh}7_IuI2H*D|ywn73Lm?g>e+LNXTI|XzW{71oox+^HWinUg=kR?G}Pzzixcd%I`z{>%q1l2ajWMDtv zHst#rwpB>S_Z#4rp=xdB1q*Wt3l##@lV&wd#ek{D3l8-1Xz_eDkNSZsPhD%$)Pp8X z7K-%hPfhN7K{XW3&|UZnbs@E287432Jl^c~?Z@WGN8lj57L}fR+JCQ*OFR_g--I45 z+jKXH0M=HCm&g%z`|ig7h_(FmLqXEO(#26W6hm#XXV%LJf;&RKG%Ky9V!sRP07W`S z7*Rvwm1_DMLI2u8lTow^?-VSFw_AtCIJApzOG@Y&thYdlTKg#-9>VFqF#yXv>2L z-%ZH;Ti#gLc-75)?_W40wDgjnw+;FInRk7UFczM=jz2J{z+P{KdZ>7&Z2er)TU-*L5Y)6=~j1E!b!0*5gC?y4Kdk z^kEvmR}+o$2ZW^a*%)ACyTD%ff9U@!JRrG~@D-rG%<8Cr-3Xy(fSmN`M?qH~5~4-L zH4=fw^b;%bJ(TrG=ZfW^>TwXZ1bjWxd7$a<8RzehWPiJe8LGu?;G#Ni+v`_X}3+D-*@Ct^`Z>#l?@9nGb6CgR&e z>5F_>2z_b|9rGn{kD&fbkhXzGtmnhTZJ?vbtHSqx;yC#0f)3T93N#%Z;veecIxd2A zGb7YOuLFmTRLjj`3(y5m>jt*BRLkjrk?fgmBko_bJB8cZ06bN%W?0H@b-KOOc7g9j rk&kLne>&)FgO^+RSo9y2L(%{F`#<%-KJ{;aZK00%pTGa_Jn+8(hI_OI literal 0 HcmV?d00001 diff --git a/DOTween.Modules.pdb b/DOTween.Modules.pdb new file mode 100644 index 0000000000000000000000000000000000000000..8cb1d773909e9b85d612adf9b15ae82258194b8b GIT binary patch literal 26392 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 DW(fmn literal 0 HcmV?d00001 diff --git a/DOTween.XML b/DOTween.XML new file mode 100644 index 0000000..ceb16e4 --- /dev/null +++ b/DOTween.XML @@ -0,0 +1,3077 @@ + + + + DOTween + + + + + Types of autoPlay behaviours + + + + No tween is automatically played + + + Only Sequences are automatically played + + + Only Tweeners are automatically played + + + All tweens are automatically played + + + + What axis to constrain in case of Vector tweens + + + + Called the first time the tween is set in a playing state, after any eventual delay + + + + Used in place of System.Func, which is not available in mscorlib. + + + + + Used in place of System.Action. + + + + + Public so it can be used by lose scripts related to DOTween (like DOTweenAnimation) + + + + + Used to separate DOTween class from the MonoBehaviour instance (in order to use static constructors on DOTween). + Contains all instance-based methods + + + + Used internally inside Unity Editor, as a trick to update DOTween's inspector at every frame + + + + Directly sets the current max capacity of Tweeners and Sequences + (meaning how many Tweeners and Sequences can be running at the same time), + so that DOTween doesn't need to automatically increase them in case the max is reached + (which might lead to hiccups when that happens). + Sequences capacity must be less or equal to Tweeners capacity + (if you pass a low Tweener capacity it will be automatically increased to match the Sequence's). + Beware: use this method only when there are no tweens running. + + Max Tweeners capacity. + Default: 200 + Max Sequences capacity. + Default: 50 + + + + This class contains a C# port of the easing equations created by Robert Penner (http://robertpenner.com/easing). + + + + + Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in: accelerating from zero velocity. + + + Current time (in frames or seconds). + + + Expected easing duration (in frames or seconds). + + Unused: here to keep same delegate for all ease types. + Unused: here to keep same delegate for all ease types. + + The eased value. + + + + + Easing equation function for a bounce (exponentially decaying parabolic bounce) easing out: decelerating from zero velocity. + + + Current time (in frames or seconds). + + + Expected easing duration (in frames or seconds). + + Unused: here to keep same delegate for all ease types. + Unused: here to keep same delegate for all ease types. + + The eased value. + + + + + Easing equation function for a bounce (exponentially decaying parabolic bounce) easing in/out: acceleration until halfway, then deceleration. + + + Current time (in frames or seconds). + + + Expected easing duration (in frames or seconds). + + Unused: here to keep same delegate for all ease types. + Unused: here to keep same delegate for all ease types. + + The eased value. + + + + + Returns a value between 0 and 1 (inclusive) based on the elapsed time and ease selected + + + + + Returns a value between 0 and 1 (inclusive) based on the elapsed time and ease selected + + + + + Used to interpret AnimationCurves as eases. + Public so it can be used by external ease factories + + + + + Behaviour in case a tween nested inside a Sequence fails and is captured by safe mode + + + + If the Sequence contains other elements, kill the failed tween but preserve the rest + + + Kill the whole Sequence + + + + Log types thrown by errors captured and prevented by safe mode + + + + No logs. NOT RECOMMENDED + + + Throw a normal log + + + Throw a warning log (default) + + + Throw an error log + + + + Additional notices passed to plugins when updating. + Public so it can be used by custom plugins. Internally, only PathPlugin uses it + + + + + None + + + + + Lets the plugin know that we restarted or rewinded + + + + + OnRewind callback behaviour (can only be set via DOTween's Utility Panel) + + + + + When calling Rewind or PlayBackwards/SmoothRewind, OnRewind callbacks will be fired only if the tween isn't already rewinded + + + + + When calling Rewind, OnRewind callbacks will always be fired, even if the tween is already rewinded. + When calling PlayBackwards/SmoothRewind instead, OnRewind callbacks will be fired only if the tween isn't already rewinded + + + + + When calling Rewind or PlayBackwards/SmoothRewind, OnRewind callbacks will always be fired, even if the tween is already rewinded + + + + + Public only so custom shortcuts can access some of these methods + + + + + INTERNAL: used by DO shortcuts and Modules to set special startup mode + + + + + INTERNAL: used by DO shortcuts and Modules to set the tween as blendable + + + + + INTERNAL: used by DO shortcuts and Modules to prevent a tween from using a From setup even if passed + + + + + Used to dispatch commands that need to be captured externally, usually by Modules + + + + + Various utils + + + + + Returns a Vector3 with z = 0 + + + + + Returns the 2D angle between two vectors + + + + + Returns a point on a circle with the given center and radius, + using Unity's circle coordinates (0° points up and increases clockwise) + + + + + Uses approximate equality on each axis instead of Unity's Vector3 equality, + because the latter fails (in some cases) when assigning a Vector3 to a transform.position and then checking it. + + + + + Looks for the type within all possible project assembly names + + + + NO-GC METHOD: changes the start value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new start value + If bigger than 0 applies it as the new tween duration + + + NO-GC METHOD: changes the end value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new end value + If TRUE the start value will become the current target's value, otherwise it will stay the same + + + NO-GC METHOD: changes the end value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new end value + If bigger than 0 applies it as the new tween duration + If TRUE the start value will become the current target's value, otherwise it will stay the same + + + NO-GC METHOD: changes the start and end value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new start value + The new end value + If bigger than 0 applies it as the new tween duration + + + + Struct that stores two colors (used for LineRenderer tweens) + + + + + Used for tween callbacks + + + + + Used for tween callbacks + + + + + Used for custom and animationCurve-based ease functions. Must return a value between 0 and 1. + + + + + Straight Quaternion plugin. Instead of using Vector3 values accepts Quaternion values directly. + Beware: doesn't work with LoopType.Incremental (neither directly nor if inside a LoopType.Incremental Sequence). + To use it, call DOTween.To with the plugin parameter overload, passing it PureQuaternionPlugin.Plug() as first parameter + (do not use any of the other public PureQuaternionPlugin methods): + DOTween.To(PureQuaternionPlugin.Plug(), ()=> myQuaternionProperty, x=> myQuaternionProperty = x, myQuaternionEndValue, duration); + + + + + Plug this plugin inside a DOTween.To call. + Example: + DOTween.To(PureQuaternionPlugin.Plug(), ()=> myQuaternionProperty, x=> myQuaternionProperty = x, myQuaternionEndValue, duration); + + + + INTERNAL: do not use + + + INTERNAL: do not use + + + INTERNAL: do not use + + + INTERNAL: do not use + + + INTERNAL: do not use + + + INTERNAL: do not use + + + INTERNAL: do not use + + + INTERNAL: do not use + + + + Extra non-tweening-related curve methods + + + + + Cubic bezier curve methods + + + + + Calculates a point along the given Cubic Bezier segment-curve. + + Segment start point + Start point's control point/handle + Segment end point + End point's control point/handle + 0-1 percentage along which to retrieve point + + + + Returns an array containing a series of points along the given Cubic Bezier segment-curve. + + Start point + Start point's control point/handle + End point + End point's control point/handle + Cloud resolution (min: 2) + + + + Calculates a series of points along the given Cubic Bezier segment-curve and adds them to the given list. + + Start point + Start point's control point/handle + End point + End point's control point/handle + Cloud resolution (min: 2) + + + + Main DOTween class. Contains static methods to create and control tweens in a generic way + + + + DOTween's version + + + If TRUE (default) makes tweens slightly slower but safer, automatically taking care of a series of things + (like targets becoming null while a tween is playing). + Default: TRUE + + + Log type when safe mode reports capturing an error and preventing it + + + Behaviour in case a tween nested inside a Sequence fails (and is caught by safe mode). + Default: NestedTweenFailureBehaviour.TryToPreserveSequence + + + If TRUE you will get a DOTween report when exiting play mode (only in the Editor). + Useful to know how many max Tweeners and Sequences you reached and optimize your final project accordingly. + Beware, this will slightly slow down your tweens while inside Unity Editor. + Default: FALSE + + + Global DOTween global timeScale (default: 1). + The final timeScale of a non-timeScaleIndependent tween is: + Unity's Time.timeScale * DOTween.timeScale * tween.timeScale + while the final timeScale of a timeScaleIndependent tween is: + DOTween.unscaledTimeScale * DOTween.timeScale * tween.timeScale + + + DOTween timeScale applied only to timeScaleIndependent tweens (default: 1). + The final timeScale of a timeScaleIndependent tween is: + DOTween.unscaledTimeScale * DOTween.timeScale * tween.timeScale + + + If TRUE, DOTween will use Time.smoothDeltaTime instead of Time.deltaTime for UpdateType.Normal and UpdateType.Late tweens + (unless they're set as timeScaleIndependent, in which case a value between the last timestep + and will be used instead). + Setting this to TRUE will lead to smoother animations. + Default: FALSE + + + If is TRUE, this indicates the max timeStep that an independent update call can last. + Setting this to TRUE will lead to smoother animations. + Default: FALSE + + + DOTween's log behaviour. + Default: LogBehaviour.ErrorsOnly + + + Used to intercept DOTween's logs. If this method isn't NULL, DOTween will call it before writing a log via Unity's own Debug log methods. + Return TRUE if you want DOTween to proceed with the log, FALSE otherwise. + This method must return a bool and accept two parameters: + - LogType: the type of Unity log that DOTween is trying to log + - object: the log message that DOTween wants to log + + + If TRUE draws path gizmos in Unity Editor (if the gizmos button is active). + Deactivate this if you want to avoid gizmos overhead while in Unity Editor + + + If TRUE activates various debug options + + + Stores the target id so it can be used to give more info in case of safeMode error capturing. + Only active if both debugMode and useSafeMode are TRUE + + + Default updateType for new tweens. + Default: UpdateType.Normal + + + Sets whether Unity's timeScale should be taken into account by default or not. + Default: false + + + Default autoPlay behaviour for new tweens. + Default: AutoPlay.All + + + Default autoKillOnComplete behaviour for new tweens. + Default: TRUE + + + Default loopType applied to all new tweens. + Default: LoopType.Restart + + + If TRUE all newly created tweens are set as recyclable, otherwise not. + Default: FALSE + + + Default ease applied to all new Tweeners (not to Sequences which always have Ease.Linear as default). + Default: Ease.InOutQuad + + + Default overshoot/amplitude used for eases + Default: 1.70158f + + + Default period used for eases + Default: 0 + + + Used internally. Assigned/removed by DOTweenComponent.Create/DestroyInstance + + + + Must be called once, before the first ever DOTween call/reference, + otherwise it will be called automatically and will use default options. + Calling it a second time won't have any effect. + You can chain SetCapacity to this method, to directly set the max starting size of Tweeners and Sequences: + DOTween.Init(false, false, LogBehaviour.Default).SetCapacity(100, 20); + + If TRUE all new tweens will be set for recycling, meaning that when killed, + instead of being destroyed, they will be put in a pool and reused instead of creating new tweens. This option allows you to avoid + GC allocations by reusing tweens, but you will have to take care of tween references, since they might result active + even if they were killed (since they might have been respawned and are now being used for other tweens). + If you want to automatically set your tween references to NULL when a tween is killed + you can use the OnKill callback like this: + .OnKill(()=> myTweenReference = null) + You can change this setting at any time by changing the static property, + or you can set the recycling behaviour for each tween separately, using: + SetRecyclable(bool recyclable) + Default: FALSE + If TRUE makes tweens slightly slower but safer, automatically taking care of a series of things + (like targets becoming null while a tween is playing). + You can change this setting at any time by changing the static property. + Default: FALSE + Type of logging to use. + You can change this setting at any time by changing the static property. + Default: ErrorsOnly + + + + Directly sets the current max capacity of Tweeners and Sequences + (meaning how many Tweeners and Sequences can be running at the same time), + so that DOTween doesn't need to automatically increase them in case the max is reached + (which might lead to hiccups when that happens). + Sequences capacity must be less or equal to Tweeners capacity + (if you pass a low Tweener capacity it will be automatically increased to match the Sequence's). + Beware: use this method only when there are no tweens running. + + Max Tweeners capacity. + Default: 200 + Max Sequences capacity. + Default: 50 + + + + Kills all tweens, clears all cached tween pools and plugins and resets the max Tweeners/Sequences capacities to the default values. + + If TRUE also destroys DOTween's gameObject and resets its initializiation, default settings and everything else + (so that next time you use it it will need to be re-initialized) + + + + Clears all cached tween pools. + + + + + Checks all active tweens to find and remove eventually invalid ones (usually because their targets became NULL) + and returns the total number of invalid tweens found and removed. + IMPORTANT: this will cause an error on UWP platform, so don't use it there + BEWARE: this is a slightly expensive operation so use it with care + + + + + Updates all tweens that are set to . + + Manual deltaTime + Unscaled delta time (used with tweens set as timeScaleIndependent) + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a property or field to the given value using a custom plugin + The plugin to use. Each custom plugin implements a static Get() method + you'll need to call to assign the correct plugin in the correct way, like this: + CustomPlugin.Get() + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens only one axis of a Vector3 to the given value using default plugins. + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + The axis to tween + + + Tweens only the alpha of a Color to the given value using default plugins + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end value to reachThe tween's duration + + + Tweens a virtual property from the given start to the given end value + and implements a setter that allows to use that value with an external method or a lambda + Example: + To(MyMethod, 0, 12, 0.5f); + Where MyMethod is a function that accepts a float parameter (which will be the result of the virtual tween) + The action to perform with the tweened value + The value to start from + The end value to reach + The duration of the virtual tween + + + + Punches a Vector3 towards the given direction and then back to the starting one + as if it was connected to the starting position via an elastic. + This tween type generates some GC allocations at startup + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The direction and strength of the punch + The duration of the tween + Indicates how much will the punch vibrate + Represents how much (0 to 1) the vector will go beyond the starting position when bouncing backwards. + 1 creates a full oscillation between the direction and the opposite decaying direction, + while 0 oscillates only between the starting position and the decaying direction + + + Shakes a Vector3 with the given values. + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The duration of the tween + The shake strength + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction and behave like a random punch. + If TRUE only shakes on the X Y axis (looks better with things like cameras). + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Vector3 with the given values. + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The duration of the tween + The shake strength on each axis + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction and behave like a random punch. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Tweens a property or field to the given values using default plugins. + Ease is applied between each segment and not as a whole. + This tween type generates some GC allocations at startup + A getter for the field or property to tween. + Example usage with lambda:()=> myProperty + A setter for the field or property to tween + Example usage with lambda:x=> myProperty = x + The end values to reach for each segment. This array must have the same length as durations + The duration of each segment. This array must have the same length as endValues + + + + Returns a new to be used for tween groups. + Mind that Sequences don't have a target applied automatically like Tweener creation shortcuts, + so if you want to be able to kill this Sequence when calling DOTween.Kill(target) you'll have to add + the target manually; you can do that directly by using the overload instead of this one + + + + + Returns a new to be used for tween groups, and allows to set a target + (because Sequences don't have their target set automatically like Tweener creation shortcuts). + That way killing/controlling tweens by target will apply to this Sequence too. + + The target of the Sequence. Relevant only for static target-based methods like DOTween.Kill(target), + useless otherwise + + + Completes all tweens and returns the number of actual tweens completed + (meaning tweens that don't have infinite loops and were not already complete) + For Sequences only: if TRUE also internal Sequence callbacks will be fired, + otherwise they will be ignored + + + Completes all tweens with the given ID or target and returns the number of actual tweens completed + (meaning the tweens that don't have infinite loops and were not already complete) + For Sequences only: if TRUE internal Sequence callbacks will be fired, + otherwise they will be ignored + + + Flips all tweens (changing their direction to forward if it was backwards and viceversa), + then returns the number of actual tweens flipped + + + Flips the tweens with the given ID or target (changing their direction to forward if it was backwards and viceversa), + then returns the number of actual tweens flipped + + + Sends all tweens to the given position (calculating also eventual loop cycles) and returns the actual tweens involved + + + Sends all tweens with the given ID or target to the given position (calculating also eventual loop cycles) + and returns the actual tweens involved + + + Kills all tweens and returns the number of actual tweens killed + If TRUE completes the tweens before killing them + + + Kills all tweens and returns the number of actual tweens killed + If TRUE completes the tweens before killing them + Eventual IDs or targets to exclude from the killing + + + Kills all tweens with the given ID or target and returns the number of actual tweens killed + If TRUE completes the tweens before killing them + + + Kills all tweens with the given target and the given ID, and returns the number of actual tweens killed + If TRUE completes the tweens before killing them + + + Pauses all tweens and returns the number of actual tweens paused + + + Pauses all tweens with the given ID or target and returns the number of actual tweens paused + (meaning the tweens that were actually playing and have been paused) + + + Plays all tweens and returns the number of actual tweens played + (meaning tweens that were not already playing or complete) + + + Plays all tweens with the given ID or target and returns the number of actual tweens played + (meaning the tweens that were not already playing or complete) + + + Plays all tweens with the given target and the given ID, and returns the number of actual tweens played + (meaning the tweens that were not already playing or complete) + + + Plays backwards all tweens and returns the number of actual tweens played + (meaning tweens that were not already started, playing backwards or rewinded) + + + Plays backwards all tweens with the given ID or target and returns the number of actual tweens played + (meaning the tweens that were not already started, playing backwards or rewinded) + + + Plays backwards all tweens with the given target and ID and returns the number of actual tweens played + (meaning the tweens that were not already started, playing backwards or rewinded) + + + Plays forward all tweens and returns the number of actual tweens played + (meaning tweens that were not already playing forward or complete) + + + Plays forward all tweens with the given ID or target and returns the number of actual tweens played + (meaning the tweens that were not already playing forward or complete) + + + Plays forward all tweens with the given target and ID and returns the number of actual tweens played + (meaning the tweens that were not already started, playing backwards or rewinded) + + + Restarts all tweens, then returns the number of actual tweens restarted + + + Restarts all tweens with the given ID or target, then returns the number of actual tweens restarted + If TRUE includes the eventual tweens delays, otherwise skips them + If >= 0 changes the startup delay of all involved tweens to this value, otherwise doesn't touch it + + + Restarts all tweens with the given target and the given ID, and returns the number of actual tweens played + (meaning the tweens that were not already playing or complete) + If TRUE includes the eventual tweens delays, otherwise skips them + If >= 0 changes the startup delay of all involved tweens to this value, otherwise doesn't touch it + + + Rewinds and pauses all tweens, then returns the number of actual tweens rewinded + (meaning tweens that were not already rewinded) + + + Rewinds and pauses all tweens with the given ID or target, then returns the number of actual tweens rewinded + (meaning the tweens that were not already rewinded) + + + Smoothly rewinds all tweens (delays excluded), then returns the number of actual tweens rewinding/rewinded + (meaning tweens that were not already rewinded). + A "smooth rewind" animates the tween to its start position, + skipping all elapsed loops (except in case of LoopType.Incremental) while keeping the animation fluent. + Note that a tween that was smoothly rewinded will have its play direction flipped + + + Smoothly rewinds all tweens (delays excluded) with the given ID or target, then returns the number of actual tweens rewinding/rewinded + (meaning the tweens that were not already rewinded). + A "smooth rewind" animates the tween to its start position, + skipping all elapsed loops (except in case of LoopType.Incremental) while keeping the animation fluent. + Note that a tween that was smoothly rewinded will have its play direction flipped + + + Toggles the play state of all tweens and returns the number of actual tweens toggled + (meaning tweens that could be played or paused, depending on the toggle state) + + + Toggles the play state of all tweens with the given ID or target and returns the number of actual tweens toggled + (meaning the tweens that could be played or paused, depending on the toggle state) + + + + Returns TRUE if a tween with the given ID or target is active. + You can also use this to know if a shortcut tween is active for a given target. + Example: + transform.DOMoveX(45, 1); // transform is automatically added as the tween target + DOTween.IsTweening(transform); // Returns true + + The target or ID to look for + If FALSE (default) returns TRUE as long as a tween for the given target/ID is active, + otherwise also requires it to be playing + + + + Returns the total number of active tweens (so both Tweeners and Sequences). + A tween is considered active if it wasn't killed, regardless if it's playing or paused + + + + + Returns the total number of active Tweeners. + A Tweener is considered active if it wasn't killed, regardless if it's playing or paused + + + + + Returns the total number of active Sequences. + A Sequence is considered active if it wasn't killed, regardless if it's playing or paused + + + + + Returns the total number of active and playing tweens. + A tween is considered as playing even if its delay is actually playing + + + + + Returns a the total number of active tweens with the given id. + + If TRUE returns only the tweens with the given ID that are currently playing + + + + Returns a list of all active tweens in a playing state. + Returns NULL if there are no active playing tweens. + Beware: each time you call this method a new list is generated, so use it for debug only + + If NULL creates a new list, otherwise clears and fills this one (and thus saves allocations) + + + + Returns a list of all active tweens in a paused state. + Returns NULL if there are no active paused tweens. + Beware: each time you call this method a new list is generated, so use it for debug only + + If NULL creates a new list, otherwise clears and fills this one (and thus saves allocations) + + + + Returns a list of all active tweens with the given id. + Returns NULL if there are no active tweens with the given id. + Beware: each time you call this method a new list is generated + + If TRUE returns only the tweens with the given ID that are currently playing + If NULL creates a new list, otherwise clears and fills this one (and thus saves allocations) + + + + Returns a list of all active tweens with the given target. + Returns NULL if there are no active tweens with the given target. + Beware: each time you call this method a new list is generated + If TRUE returns only the tweens with the given target that are currently playing + If NULL creates a new list, otherwise clears and fills this one (and thus saves allocations) + + + + + Creates virtual tweens that can be used to change other elements via their OnUpdate calls + + + + + Tweens a virtual float. + You can add regular settings to the generated tween, + but do not use OnUpdate or you will overwrite the onVirtualUpdate parameter + + The value to start from + The value to tween to + The duration of the tween + A callback which must accept a parameter of type float, called at each update + + + + Tweens a virtual int. + You can add regular settings to the generated tween, + but do not use OnUpdate or you will overwrite the onVirtualUpdate parameter + + The value to start from + The value to tween to + The duration of the tween + A callback which must accept a parameter of type int, called at each update + + + + Tweens a virtual Vector2. + You can add regular settings to the generated tween, + but do not use OnUpdate or you will overwrite the onVirtualUpdate parameter + + The value to start from + The value to tween to + The duration of the tween + A callback which must accept a parameter of type Vector3, called at each update + + + + Tweens a virtual Vector3. + You can add regular settings to the generated tween, + but do not use OnUpdate or you will overwrite the onVirtualUpdate parameter + + The value to start from + The value to tween to + The duration of the tween + A callback which must accept a parameter of type Vector3, called at each update + + + + Tweens a virtual Color. + You can add regular settings to the generated tween, + but do not use OnUpdate or you will overwrite the onVirtualUpdate parameter + + The value to start from + The value to tween to + The duration of the tween + A callback which must accept a parameter of type Color, called at each update + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The type of ease + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The type of ease + Eventual overshoot to use with Back ease + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The type of ease + Eventual amplitude to use with Elastic easeType + Eventual period to use with Elastic easeType + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The AnimationCurve to use for ease + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The type of ease + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The type of ease + Eventual overshoot to use with Back ease + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The type of ease + Eventual amplitude to use with Elastic easeType + Eventual period to use with Elastic easeType + + + Returns a value based on the given ease and lifetime percentage (0 to 1) + The value to start from when lifetimePercentage is 0 + The value to reach when lifetimePercentage is 1 + The time percentage (0 to 1) at which the value should be taken + The AnimationCurve to use for ease + + + Fires the given callback after the given time. + Callback delay + Callback to fire when the delay has expired + If TRUE (default) ignores Unity's timeScale + + + + Don't assign this! It's assigned automatically when creating 0 duration tweens + + + + + Don't assign this! It's assigned automatically when setting the ease to an AnimationCurve or to a custom ease function + + + + + Allows to wrap ease method in special ways, adding extra features + + + + + Converts the given ease so that it also creates a stop-motion effect, by playing the tween at the given FPS + + FPS at which the tween should be played + Ease type + + + + Converts the given ease so that it also creates a stop-motion effect, by playing the tween at the given FPS + + FPS at which the tween should be played + AnimationCurve to use for the ease + + + + Converts the given ease so that it also creates a stop-motion effect, by playing the tween at the given FPS + + FPS at which the tween should be played + Custom ease function to use + + + + Used to allow method chaining with DOTween.Init + + + + + Directly sets the current max capacity of Tweeners and Sequences + (meaning how many Tweeners and Sequences can be running at the same time), + so that DOTween doesn't need to automatically increase them in case the max is reached + (which might lead to hiccups when that happens). + Sequences capacity must be less or equal to Tweeners capacity + (if you pass a low Tweener capacity it will be automatically increased to match the Sequence's). + Beware: use this method only when there are no tweens running. + + Max Tweeners capacity. + Default: 200 + Max Sequences capacity. + Default: 50 + + + + Behaviour that can be assigned when chaining a SetLink to a tween + + + + Pauses the tween when the link target is disabled + + + Pauses the tween when the link target is disabled, plays it when it's enabled + + + Pauses the tween when the link target is disabled, restarts it when it's enabled + + + Plays the tween when the link target is enabled + + + Restarts the tween when the link target is enabled + + + Kills the tween when the link target is disabled + + + Kills the tween when the link target is destroyed (becomes NULL). This is always active even if another behaviour is chosen + + + Completes the tween when the link target is disabled + + + Completes and kills the tween when the link target is disabled + + + Rewinds the tween (delay excluded) when the link target is disabled + + + Rewinds and kills the tween when the link target is disabled + + + + Path mode (used to determine correct LookAt orientation) + + + + Ignores the path mode (and thus LookAt behaviour) + + + Regular 3D path + + + 2D top-down path + + + 2D side-scroller path + + + + Type of path to use with DOPath tweens + + + + Linear, composed of straight segments between each waypoint + + + Curved path (which uses Catmull-Rom curves) + + + EXPERIMENTAL: Curved path (which uses Cubic Bezier curves, where each point requires two extra control points) + + + + Tweens a Vector2 along a circle. + EndValue represents the center of the circle, start and end value degrees are inside options + ChangeValue x is changeValue°, y is unused + + + + + Path control point + + + + + Path waypoints (modified by PathPlugin when setting relative end/change value or by CubicBezierDecoder) and by DOTweenPathInspector + + + + + Minimum input points necessary to create the path (doesn't correspond to actual waypoints required) + + + + + Gets the point on the path at the given percentage (0 to 1) + + The percentage (0 to 1) at which to get the point + If TRUE constant speed is taken into account, otherwise not + + + + Base interface for all tween plugins options + + + + Resets the plugin + + + + This plugin generates some GC allocations at startup + + + + + Path plugin works exclusively with Transforms + + + + + Rotation mode used with DORotate methods + + + + + Fastest way that never rotates beyond 360° + + + + + Fastest way that rotates beyond 360° + + + + + Adds the given rotation to the transform using world axis and an advanced precision mode + (like when using transform.Rotate(Space.World)). + In this mode the end value is is always considered relative + + + + + Adds the given rotation to the transform's local axis + (like when rotating an object with the "local" switch enabled in Unity's editor or using transform.Rotate(Space.Self)). + In this mode the end value is is always considered relative + + + + + Type of scramble to apply to string tweens + + + + + No scrambling of characters + + + + + A-Z + a-z + 0-9 characters + + + + + A-Z characters + + + + + a-z characters + + + + + 0-9 characters + + + + + Custom characters + + + + + Type of randomness to apply to a shake tween + + + + Default, full randomness + + + Creates a more balanced randomness that looks more harmonic + + + + Methods that extend Tween objects and allow to control or get data from them + + + + Completes the tween + + + Completes the tween + For Sequences only: if TRUE also internal Sequence callbacks will be fired, + otherwise they will be ignored + + + Flips the direction of this tween (backwards if it was going forward or viceversa) + + + Forces the tween to initialize its settings immediately + + + Send the tween to the given position in time + Time position to reach + (if higher than the whole tween duration the tween will simply reach its end) + If TRUE will play the tween after reaching the given position, otherwise it will pause it + + + Send the tween to the given position in time while also executing any callback between the previous time position and the new one + Time position to reach + (if higher than the whole tween duration the tween will simply reach its end) + If TRUE will play the tween after reaching the given position, otherwise it will pause it + + + Kills the tween + If TRUE completes the tween before killing it + + + + Forces this tween to update manually, regardless of the set via SetUpdate. + Note that the tween will still be subject to normal tween rules, so if for example it's paused this method will do nothing. + Also note that if you only want to update this tween instance manually you'll have to set it to anyway, + so that it's not updated automatically. + + Manual deltaTime + Unscaled delta time (used with tweens set as timeScaleIndependent) + + + Pauses the tween + + + Plays the tween + + + Sets the tween in a backwards direction and plays it + + + Sets the tween in a forward direction and plays it + + + Restarts the tween from the beginning + Ignored in case of Sequences. If TRUE includes the eventual tween delay, otherwise skips it + Ignored in case of Sequences. If >= 0 changes the startup delay to this value, otherwise doesn't touch it + + + Rewinds and pauses the tween + Ignored in case of Sequences. If TRUE includes the eventual tween delay, otherwise skips it + + + Smoothly rewinds the tween (delays excluded). + A "smooth rewind" animates the tween to its start position, + skipping all elapsed loops (except in case of LoopType.Incremental) while keeping the animation fluent. + If called on a tween who is still waiting for its delay to happen, it will simply set the delay to 0 and pause the tween. + Note that a tween that was smoothly rewinded will have its play direction flipped + + + Plays the tween if it was paused, pauses it if it was playing + + + Send a path tween to the given waypoint. + Has no effect if this is not a path tween. + BEWARE, this is a special utility method: + it works only with Linear eases. Also, the lookAt direction might be wrong after calling this and might need to be set manually + (because it relies on a smooth path movement and doesn't work well with jumps that encompass dramatic direction changes) + Waypoint index to reach + (if higher than the max waypoint index the tween will simply go to the last one) + If TRUE will play the tween after reaching the given waypoint, otherwise it will pause it + + + + Creates a yield instruction that waits until the tween is killed or complete. + It can be used inside a coroutine as a yield. + Example usage:yield return myTween.WaitForCompletion(); + + + + + Creates a yield instruction that waits until the tween is killed or rewinded. + It can be used inside a coroutine as a yield. + Example usage:yield return myTween.WaitForRewind(); + + + + + Creates a yield instruction that waits until the tween is killed. + It can be used inside a coroutine as a yield. + Example usage:yield return myTween.WaitForKill(); + + + + + Creates a yield instruction that waits until the tween is killed or has gone through the given amount of loops. + It can be used inside a coroutine as a yield. + Example usage:yield return myTween.WaitForElapsedLoops(2); + + Elapsed loops to wait for + + + + Creates a yield instruction that waits until the tween is killed or has reached the given position (loops included, delays excluded). + It can be used inside a coroutine as a yield. + Example usage:yield return myTween.WaitForPosition(2.5f); + + Position (loops included, delays excluded) to wait for + + + + Creates a yield instruction that waits until the tween is killed or started + (meaning when the tween is set in a playing state the first time, after any eventual delay). + It can be used inside a coroutine as a yield. + Example usage:yield return myTween.WaitForStart(); + + + + Returns the total number of loops completed by this tween + + + Returns the eventual delay set for this tween + + + Returns the eventual elapsed delay set for this tween + + + Returns the duration of this tween (delays excluded). + NOTE: when using settings like SpeedBased, the duration will be recalculated when the tween starts + If TRUE returns the full duration loops included, + otherwise the duration of a single loop cycle + + + Returns the elapsed time for this tween (delays exluded) + If TRUE returns the elapsed time since startup loops included, + otherwise the elapsed time within the current loop cycle + + + Returns the elapsed percentage (0 to 1) of this tween (delays exluded) + If TRUE returns the elapsed percentage since startup loops included, + otherwise the elapsed percentage within the current loop cycle + + + Returns the elapsed percentage (0 to 1) of this tween (delays exluded), + based on a single loop, and calculating eventual backwards Yoyo loops as 1 to 0 instead of 0 to 1 + + + Returns FALSE if this tween has been killed or is NULL, TRUE otherwise. + BEWARE: if this tween is recyclable it might have been spawned again for another use and thus return TRUE anyway. + When working with recyclable tweens you should take care to know when a tween has been killed and manually set your references to NULL. + If you want to be sure your references are set to NULL when a tween is killed you can use the OnKill callback like this: + .OnKill(()=> myTweenReference = null) + + + Returns TRUE if this tween was reversed and is set to go backwards + + + NOTE: To check if a tween was simply set to go backwards see . + Returns TRUE if this tween is going backwards for any of these reasons: + - The tween was reversed and is going backwards on a straight loop + - The tween was reversed and is going backwards on an odd Yoyo loop + - The tween is going forward but on an even Yoyo loop + IMPORTANT: if used inside a tween's callback, this will return a result concerning the exact frame when it's asked, + so for example in a callback at the end of a Yoyo loop step this method will never return FALSE + because the frame will never end exactly there and the tween will already be going backwards when the callback is fired + + + Returns TRUE if the tween is complete + (silently fails and returns FALSE if the tween has been killed) + + + Returns TRUE if this tween has been initialized + + + Returns TRUE if this tween is playing + + + Returns the total number of loops set for this tween + (returns -1 if the loops are infinite) + + + + Returns a point on a path based on the given path percentage. + Returns Vector3.zero if this is not a path tween, if the tween is invalid, or if the path is not yet initialized. + A path is initialized after its tween starts, or immediately if the tween was created with the Path Editor (DOTween Pro feature). + You can force a path to be initialized by calling myTween.ForceInit(). + + Percentage of the path (0 to 1) on which to get the point + + + + Returns an array of points that can be used to draw the path. + Note that this method generates allocations, because it creates a new array. + Returns NULL if this is not a path tween, if the tween is invalid, or if the path is not yet initialized. + A path is initialized after its tween starts, or immediately if the tween was created with the Path Editor (DOTween Pro feature). + You can force a path to be initialized by calling myTween.ForceInit(). + + How many points to create for each path segment (waypoint to waypoint). + Only used in case of non-Linear paths + + + + Returns the length of a path. + Returns -1 if this is not a path tween, if the tween is invalid, or if the path is not yet initialized. + A path is initialized after its tween starts, or immediately if the tween was created with the Path Editor (DOTween Pro feature). + You can force a path to be initialized by calling myTween.ForceInit(). + + + + + Types of loop + + + + Each loop cycle restarts from the beginning + + + The tween moves forward and backwards at alternate cycles + + + Continuously increments the tween at the end of each loop cycle (A to B, B to B+(A-B), and so on), thus always moving "onward". + In case of String tweens works only if the tween is set as relative + + + + Controls other tweens as a group + + + + + Methods that extend known Unity objects and allow to directly create and control tweens from their instances + + + + Tweens a Camera's aspect to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's backgroundColor to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's farClipPlane to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's fieldOfView to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's nearClipPlane to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's orthographicSize to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's pixelRect to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Camera's rect to the given value. + Also stores the camera as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Shakes a Camera's localPosition along its relative X Y axes with the given values. + Also stores the camera as the tween's target so it can be used for filtered operations + The duration of the tween + The shake strength + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Camera's localPosition along its relative X Y axes with the given values. + Also stores the camera as the tween's target so it can be used for filtered operations + The duration of the tween + The shake strength on each axis + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Camera's localRotation. + Also stores the camera as the tween's target so it can be used for filtered operations + The duration of the tween + The shake strength + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Camera's localRotation. + Also stores the camera as the tween's target so it can be used for filtered operations + The duration of the tween + The shake strength on each axis + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Tweens a Light's color to the given value. + Also stores the light as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Light's intensity to the given value. + Also stores the light as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Light's shadowStrength to the given value. + Also stores the light as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a LineRenderer's color to the given value. + Also stores the LineRenderer as the tween's target so it can be used for filtered operations. + Note that this method requires to also insert the start colors for the tween, + since LineRenderers have no way to get them. + The start value to tween from + The end value to reachThe duration of the tween + + + Tweens a Material's color to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Material's named color property to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The name of the material property to tween (like _Tint or _SpecColor) + The duration of the tween + + + Tweens a Material's named color property with the given ID to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The ID of the material property to tween (also called nameID in Unity's manual) + The duration of the tween + + + Tweens a Material's alpha color to the given value + (will have no effect unless your material supports transparency). + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Material's alpha color to the given value + (will have no effect unless your material supports transparency). + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The name of the material property to tween (like _Tint or _SpecColor) + The duration of the tween + + + Tweens a Material's alpha color with the given ID to the given value + (will have no effect unless your material supports transparency). + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The ID of the material property to tween (also called nameID in Unity's manual) + The duration of the tween + + + Tweens a Material's named float property to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The name of the material property to tween + The duration of the tween + + + Tweens a Material's named float property with the given ID to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The ID of the material property to tween (also called nameID in Unity's manual) + The duration of the tween + + + Tweens a Material's texture offset to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The duration of the tween + + + Tweens a Material's named texture offset property to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The name of the material property to tween + The duration of the tween + + + Tweens a Material's texture scale to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The duration of the tween + + + Tweens a Material's named texture scale property to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The name of the material property to tween + The duration of the tween + + + Tweens a Material's named Vector property to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The name of the material property to tween + The duration of the tween + + + Tweens a Material's named Vector property with the given ID to the given value. + Also stores the material as the tween's target so it can be used for filtered operations + The end value to reach + The ID of the material property to tween (also called nameID in Unity's manual) + The duration of the tween + + + Tweens a TrailRenderer's startWidth/endWidth to the given value. + Also stores the TrailRenderer as the tween's target so it can be used for filtered operations + The end startWidth to reachThe end endWidth to reach + The duration of the tween + + + Tweens a TrailRenderer's time to the given value. + Also stores the TrailRenderer as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Transform's position to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's X position to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's Y position to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's Z position to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's localPosition to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's X localPosition to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's Y localPosition to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's Z localPosition to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's rotation to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + Rotation mode + + + Tweens a Transform's rotation to the given value using pure quaternion values. + Also stores the transform as the tween's target so it can be used for filtered operations. + PLEASE NOTE: DORotate, which takes Vector3 values, is the preferred rotation method. + This method was implemented for very special cases, and doesn't support LoopType.Incremental loops + (neither for itself nor if placed inside a LoopType.Incremental Sequence) + + The end value to reachThe duration of the tween + + + Tweens a Transform's localRotation to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + Rotation mode + + + Tweens a Transform's rotation to the given value using pure quaternion values. + Also stores the transform as the tween's target so it can be used for filtered operations. + PLEASE NOTE: DOLocalRotate, which takes Vector3 values, is the preferred rotation method. + This method was implemented for very special cases, and doesn't support LoopType.Incremental loops + (neither for itself nor if placed inside a LoopType.Incremental Sequence) + + The end value to reachThe duration of the tween + + + Tweens a Transform's localScale to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Transform's localScale uniformly to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Transform's X localScale to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Transform's Y localScale to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Transform's Z localScale to the given value. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Transform's rotation so that it will look towards the given world position. + Also stores the transform as the tween's target so it can be used for filtered operations + The position to look atThe duration of the tween + Eventual axis constraint for the rotation + The vector that defines in which direction up is (default: Vector3.up) + + + EXPERIMENTAL Tweens a Transform's rotation so that it will look towards the given world position, + while also updating the lookAt position every frame + (contrary to which calculates the lookAt rotation only once, when the tween starts). + Also stores the transform as the tween's target so it can be used for filtered operations + The position to look atThe duration of the tween + Eventual axis constraint for the rotation + The vector that defines in which direction up is (default: Vector3.up) + + + Punches a Transform's localPosition towards the given direction and then back to the starting one + as if it was connected to the starting position via an elastic. + The direction and strength of the punch (added to the Transform's current position) + The duration of the tween + Indicates how much will the punch vibrate + Represents how much (0 to 1) the vector will go beyond the starting position when bouncing backwards. + 1 creates a full oscillation between the punch direction and the opposite direction, + while 0 oscillates only between the punch and the start position + If TRUE the tween will smoothly snap all values to integers + + + Punches a Transform's localScale towards the given size and then back to the starting one + as if it was connected to the starting scale via an elastic. + The punch strength (added to the Transform's current scale) + The duration of the tween + Indicates how much will the punch vibrate + Represents how much (0 to 1) the vector will go beyond the starting size when bouncing backwards. + 1 creates a full oscillation between the punch scale and the opposite scale, + while 0 oscillates only between the punch scale and the start scale + + + Punches a Transform's localRotation towards the given size and then back to the starting one + as if it was connected to the starting rotation via an elastic. + The punch strength (added to the Transform's current rotation) + The duration of the tween + Indicates how much will the punch vibrate + Represents how much (0 to 1) the vector will go beyond the starting rotation when bouncing backwards. + 1 creates a full oscillation between the punch rotation and the opposite rotation, + while 0 oscillates only between the punch and the start rotation + + + Shakes a Transform's localPosition with the given values. + The duration of the tween + The shake strength + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the tween will smoothly snap all values to integers + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Transform's localPosition with the given values. + The duration of the tween + The shake strength on each axis + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the tween will smoothly snap all values to integers + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Transform's localRotation. + The duration of the tween + The shake strength + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Transform's localRotation. + The duration of the tween + The shake strength on each axis + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Transform's localScale. + The duration of the tween + The shake strength + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Shakes a Transform's localScale. + The duration of the tween + The shake strength on each axis + Indicates how much will the shake vibrate + Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware). + Setting it to 0 will shake along a single direction. + If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not + Randomness mode + + + Tweens a Transform's position to the given value, while also applying a jump effect along the Y axis. + Returns a Sequence instead of a Tweener. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reach + Power of the jump (the max height of the jump is represented by this plus the final Y offset) + Total number of jumps + The duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's localPosition to the given value, while also applying a jump effect along the Y axis. + Returns a Sequence instead of a Tweener. + Also stores the transform as the tween's target so it can be used for filtered operations + The end value to reach + Power of the jump (the max height of the jump is represented by this plus the final Y offset) + Total number of jumps + The duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's position through the given path waypoints, using the chosen path algorithm. + Also stores the transform as the tween's target so it can be used for filtered operations + The waypoints to go through + The duration of the tween + The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points) + The path mode: 3D, side-scroller 2D, top-down 2D + The resolution of the path (useless in case of Linear paths): higher resolutions make for more detailed curved paths but are more expensive. + Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints + The color of the path (shown when gizmos are active in the Play panel and the tween is running) + + + Tweens a Transform's localPosition through the given path waypoints, using the chosen path algorithm. + Also stores the transform as the tween's target so it can be used for filtered operations + The waypoint to go through + The duration of the tween + The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points) + The path mode: 3D, side-scroller 2D, top-down 2D + The resolution of the path: higher resolutions make for more detailed curved paths but are more expensive. + Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints + The color of the path (shown when gizmos are active in the Play panel and the tween is running) + + + IMPORTANT: Unless you really know what you're doing, you should use the overload that accepts a Vector3 array instead. + Tweens a Transform's position via the given path. + Also stores the transform as the tween's target so it can be used for filtered operations + The path to use + The duration of the tween + The path mode: 3D, side-scroller 2D, top-down 2D + + + IMPORTANT: Unless you really know what you're doing, you should use the overload that accepts a Vector3 array instead. + Tweens a Transform's localPosition via the given path. + Also stores the transform as the tween's target so it can be used for filtered operations + The path to use + The duration of the tween + The path mode: 3D, side-scroller 2D, top-down 2D + + + Tweens a Tween's timeScale to the given value. + Also stores the Tween as the tween's target so it can be used for filtered operations + The end value to reachThe duration of the tween + + + Tweens a Light's color to the given value, + in a way that allows other DOBlendableColor tweens to work together on the same target, + instead than fight each other as multiple DOColor would do. + Also stores the Light as the tween's target so it can be used for filtered operations + The value to tween toThe duration of the tween + + + Tweens a Material's color to the given value, + in a way that allows other DOBlendableColor tweens to work together on the same target, + instead than fight each other as multiple DOColor would do. + Also stores the Material as the tween's target so it can be used for filtered operations + The value to tween toThe duration of the tween + + + Tweens a Material's named color property to the given value, + in a way that allows other DOBlendableColor tweens to work together on the same target, + instead than fight each other as multiple DOColor would do. + Also stores the Material as the tween's target so it can be used for filtered operations + The value to tween to + The name of the material property to tween (like _Tint or _SpecColor) + The duration of the tween + + + Tweens a Material's named color property with the given ID to the given value, + in a way that allows other DOBlendableColor tweens to work together on the same target, + instead than fight each other as multiple DOColor would do. + Also stores the Material as the tween's target so it can be used for filtered operations + The value to tween to + The ID of the material property to tween (also called nameID in Unity's manual) + The duration of the tween + + + Tweens a Transform's position BY the given value (as if you chained a SetRelative), + in a way that allows other DOBlendableMove tweens to work together on the same target, + instead than fight each other as multiple DOMove would do. + Also stores the transform as the tween's target so it can be used for filtered operations + The value to tween byThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + Tweens a Transform's localPosition BY the given value (as if you chained a SetRelative), + in a way that allows other DOBlendableMove tweens to work together on the same target, + instead than fight each other as multiple DOMove would do. + Also stores the transform as the tween's target so it can be used for filtered operations + The value to tween byThe duration of the tween + If TRUE the tween will smoothly snap all values to integers + + + EXPERIMENTAL METHOD - Tweens a Transform's rotation BY the given value (as if you chained a SetRelative), + in a way that allows other DOBlendableRotate tweens to work together on the same target, + instead than fight each other as multiple DORotate would do. + Also stores the transform as the tween's target so it can be used for filtered operations + The value to tween byThe duration of the tween + Rotation mode + + + EXPERIMENTAL METHOD - Tweens a Transform's lcoalRotation BY the given value (as if you chained a SetRelative), + in a way that allows other DOBlendableRotate tweens to work together on the same target, + instead than fight each other as multiple DORotate would do. + Also stores the transform as the tween's target so it can be used for filtered operations + The value to tween byThe duration of the tween + Rotation mode + + + Punches a Transform's localRotation BY the given value and then back to the starting one + as if it was connected to the starting rotation via an elastic. Does it in a way that allows other + DOBlendableRotate tweens to work together on the same target + The punch strength (added to the Transform's current rotation) + The duration of the tween + Indicates how much will the punch vibrate + Represents how much (0 to 1) the vector will go beyond the starting rotation when bouncing backwards. + 1 creates a full oscillation between the punch rotation and the opposite rotation, + while 0 oscillates only between the punch and the start rotation + + + Tweens a Transform's localScale BY the given value (as if you chained a SetRelative), + in a way that allows other DOBlendableScale tweens to work together on the same target, + instead than fight each other as multiple DOScale would do. + Also stores the transform as the tween's target so it can be used for filtered operations + The value to tween byThe duration of the tween + + + + Completes all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens completed + (meaning the tweens that don't have infinite loops and were not already complete) + + For Sequences only: if TRUE also internal Sequence callbacks will be fired, + otherwise they will be ignored + + + + Completes all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens completed + (meaning the tweens that don't have infinite loops and were not already complete) + + For Sequences only: if TRUE also internal Sequence callbacks will be fired, + otherwise they will be ignored + + + + Kills all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens killed. + + If TRUE completes the tween before killing it + + + + Kills all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens killed. + + If TRUE completes the tween before killing it + + + + Flips the direction (backwards if it was going forward or viceversa) of all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens flipped. + + + + + Flips the direction (backwards if it was going forward or viceversa) of all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens flipped. + + + + + Sends to the given position all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens involved. + + Time position to reach + (if higher than the whole tween duration the tween will simply reach its end) + If TRUE will play the tween after reaching the given position, otherwise it will pause it + + + + Sends to the given position all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens involved. + + Time position to reach + (if higher than the whole tween duration the tween will simply reach its end) + If TRUE will play the tween after reaching the given position, otherwise it will pause it + + + + Pauses all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens paused. + + + + + Pauses all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens paused. + + + + + Plays all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens played. + + + + + Plays all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens played. + + + + + Plays backwards all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens played. + + + + + Plays backwards all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens played. + + + + + Plays forward all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens played. + + + + + Plays forward all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens played. + + + + + Restarts all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens restarted. + + + + + Restarts all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens restarted. + + + + + Rewinds all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens rewinded. + + + + + Rewinds all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens rewinded. + + + + + Smoothly rewinds all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens rewinded. + + + + + Smoothly rewinds all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens rewinded. + + + + + Toggles the paused state (plays if it was paused, pauses if it was playing) of all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens involved. + + + + + Toggles the paused state (plays if it was paused, pauses if it was playing) of all tweens that have this target as a reference + (meaning tweens that were started from this target, or that had this target added as an Id) + and returns the total number of tweens involved. + + + + + This class serves only as a utility class to store tween settings to apply on multiple tweens. + It is in no way needed otherwise, since you can directly apply tween settings to a tween via chaining + + + + A variable you can eventually Clear and reuse when needed, + to avoid instantiating TweenParams objects + + + Creates a new TweenParams object, which you can use to store tween settings + to pass to multiple tweens via myTween.SetAs(myTweenParms) + + + Clears and resets this TweenParams instance using default values, + so it can be reused without instantiating another one + + + Sets the autoKill behaviour of the tween. + Has no effect if the tween has already started + If TRUE the tween will be automatically killed when complete + + + Sets an ID for the tween, which can then be used as a filter with DOTween's static methods. + The ID to assign to this tween. Can be an int, a string, an object or anything else. + + + Sets an ID for the tween, which can then be used as a filter with DOTween's static methods. + The ID to assign to this tween. Can be an int, a string, an object or anything else. + + + Sets an ID for the tween, which can then be used as a filter with DOTween's static methods. + The ID to assign to this tween. Can be an int, a string, an object or anything else. + + + Sets the target for the tween, which can then be used as a filter with DOTween's static methods. + IMPORTANT: use it with caution. If you just want to set an ID for the tween use SetId instead. + When using shorcuts the shortcut target is already assigned as the tween's target, + so using this method will overwrite it and prevent shortcut-operations like myTarget.DOPause from working correctly. + The target to assign to this tween. Can be an int, a string, an object or anything else. + + + Sets the looping options for the tween. + Has no effect if the tween has already started + Number of cycles to play (-1 for infinite - will be converted to 1 in case the tween is nested in a Sequence) + Loop behaviour type (default: LoopType.Restart) + + + Sets the ease of the tween. + If applied to Sequences eases the whole sequence animation + Eventual overshoot or amplitude to use with Back or Elastic easeType (default is 1.70158) + Eventual period to use with Elastic easeType (default is 0) + + + Sets the ease of the tween using an AnimationCurve. + If applied to Sequences eases the whole sequence animation + + + Sets the ease of the tween using a custom ease function. + If applied to Sequences eases the whole sequence animation + + + Sets the recycling behaviour for the tween. + If TRUE the tween will be recycled after being killed, otherwise it will be destroyed. + + + Sets the update type to the one defined in DOTween.defaultUpdateType (UpdateType.Normal unless changed) + and lets you choose if it should be independent from Unity's Time.timeScale + If TRUE the tween will ignore Unity's Time.timeScale + + + Sets the type of update (default or independent) for the tween + The type of update (default: UpdateType.Normal) + If TRUE the tween will ignore Unity's Time.timeScale + + + Sets the onStart callback for the tween. + Called the first time the tween is set in a playing state, after any eventual delay + + + Sets the onPlay callback for the tween. + Called when the tween is set in a playing state, after any eventual delay. + Also called each time the tween resumes playing from a paused state + + + Sets the onRewind callback for the tween. + Called when the tween is rewinded, + either by calling Rewind or by reaching the start position while playing backwards. + Rewinding a tween that is already rewinded will not fire this callback + + + Sets the onUpdate callback for the tween. + Called each time the tween updates + + + Sets the onStepComplete callback for the tween. + Called the moment the tween completes one loop cycle, even when going backwards + + + Sets the onComplete callback for the tween. + Called the moment the tween reaches its final forward position, loops included + + + Sets the onKill callback for the tween. + Called the moment the tween is killed + + + Sets the onWaypointChange callback for the tween. + Called when a path tween reaches a new waypoint + + + Sets a delayed startup for the tween. + Has no effect on Sequences or if the tween has already started + + + If isRelative is TRUE sets the tween as relative + (the endValue will be calculated as startValue + endValue instead than being used directly). + Has no effect on Sequences or if the tween has already started + + + If isSpeedBased is TRUE sets the tween as speed based + (the duration will represent the number of units the tween moves x second). + Has no effect on Sequences, nested tweens, or if the tween has already started + + + + Methods that extend Tween objects and allow to set their parameters + + + + Sets the autoKill behaviour of the tween to TRUE. + Has no effect if the tween has already started or if it's added to a Sequence + + + Sets the autoKill behaviour of the tween. + Has no effect if the tween has already started or if it's added to a Sequence + If TRUE the tween will be automatically killed when complete + + + Sets an ID for the tween (), which can then be used as a filter with DOTween's static methods. + The ID to assign to this tween. Can be an int, a string, an object or anything else. + + + Sets a string ID for the tween (), which can then be used as a filter with DOTween's static methods. + Filtering via string is 2X faster than using an object as an ID (using the alternate obejct overload) + The string ID to assign to this tween. + + + Sets an int ID for the tween (), which can then be used as a filter with DOTween's static methods. + Filtering via int is 4X faster than via object, 2X faster than via string (using the alternate object/string overloads) + The int ID to assign to this tween. + + + Allows to link this tween to a GameObject + so that it will be automatically killed when the GameObject is destroyed. + Has no effect if the tween is added to a Sequence + The link target (unrelated to the target set via SetTarget) + + + Allows to link this tween to a GameObject and assign a behaviour depending on it. + This will also automatically kill the tween when the GameObject is destroyed. + Has no effect if the tween is added to a Sequence + The link target (unrelated to the target set via SetTarget) + The behaviour to use ( is always evaluated even if you choose another one) + + + Sets the target for the tween, which can then be used as a filter with DOTween's static methods. + IMPORTANT: use it with caution. If you just want to set an ID for the tween use SetId instead. + When using shorcuts the shortcut target is already assigned as the tween's target, + so using this method will overwrite it and prevent shortcut-operations like myTarget.DOPause from working correctly. + The target to assign to this tween. Can be an int, a string, an object or anything else. + + + Sets the looping options for the tween. + Has no effect if the tween has already started + Number of cycles to play (-1 for infinite - will be converted to 1 in case the tween is nested in a Sequence) + + + Sets the looping options for the tween. + Has no effect if the tween has already started + Number of cycles to play (-1 for infinite - will be converted to 1 in case the tween is nested in a Sequence) + Loop behaviour type (default: LoopType.Restart) + + + Sets the ease of the tween. + If applied to Sequences eases the whole sequence animation + + + Sets the ease of the tween. + If applied to Sequences eases the whole sequence animation + + Eventual overshoot to use with Back or Flash ease (default is 1.70158 - 1 for Flash). + In case of Flash ease it must be an intenger and sets the total number of flashes that will happen. + Using an even number will complete the tween on the starting value, while an odd one will complete it on the end value. + + + + Sets the ease of the tween. + If applied to Sequences eases the whole sequence animation + Eventual amplitude to use with Elastic easeType or overshoot to use with Flash easeType (default is 1.70158 - 1 for Flash). + In case of Flash ease it must be an integer and sets the total number of flashes that will happen. + Using an even number will complete the tween on the starting value, while an odd one will complete it on the end value. + + Eventual period to use with Elastic or Flash easeType (default is 0). + In case of Flash ease it indicates the power in time of the ease, and must be between -1 and 1. + 0 is balanced, 1 weakens the ease with time, -1 starts the ease weakened and gives it power towards the end. + + + + Sets the ease of the tween using an AnimationCurve. + If applied to Sequences eases the whole sequence animation + + + Sets the ease of the tween using a custom ease function (which must return a value between 0 and 1). + If applied to Sequences eases the whole sequence animation + + + Allows the tween to be recycled after being killed. + + + Sets the recycling behaviour for the tween. + If TRUE the tween will be recycled after being killed, otherwise it will be destroyed. + + + Sets the update type to UpdateType.Normal and lets you choose if it should be independent from Unity's Time.timeScale + If TRUE the tween will ignore Unity's Time.timeScale + + + Sets the type of update for the tween + The type of update (defalt: UpdateType.Normal) + + + Sets the type of update for the tween and lets you choose if it should be independent from Unity's Time.timeScale + The type of update + If TRUE the tween will ignore Unity's Time.timeScale + + + EXPERIMENTAL: inverts this tween, so that it will play from the end to the beginning + (playing it backwards will actually play it from the beginning to the end). + Has no effect if the tween has already started or if it's added to a Sequence + + + EXPERIMENTAL: inverts this tween, so that it will play from the end to the beginning + (playing it backwards will actually play it from the beginning to the end). + Has no effect if the tween has already started or if it's added to a Sequence + If TRUE the tween will be inverted, otherwise it won't + + + Sets the onStart callback for the tween, clearing any previous onStart callback that was set. + Called the first time the tween is set in a playing state, after any eventual delay + + + Sets the onPlay callback for the tween, clearing any previous onPlay callback that was set. + Called when the tween is set in a playing state, after any eventual delay. + Also called each time the tween resumes playing from a paused state + + + Sets the onPause callback for the tween, clearing any previous onPause callback that was set. + Called when the tween state changes from playing to paused. + If the tween has autoKill set to FALSE, this is called also when the tween reaches completion. + + + Sets the onRewind callback for the tween, clearing any previous onRewind callback that was set. + Called when the tween is rewinded, + either by calling Rewind or by reaching the start position while playing backwards. + Rewinding a tween that is already rewinded will not fire this callback + + + Sets the onUpdate callback for the tween, clearing any previous onUpdate callback that was set. + Called each time the tween updates + + + Sets the onStepComplete callback for the tween, clearing any previous onStepComplete callback that was set. + Called the moment the tween completes one loop cycle, even when going backwards + + + Sets the onComplete callback for the tween, clearing any previous onComplete callback that was set. + Called the moment the tween reaches its final forward position, loops included + + + Sets the onKill callback for the tween, clearing any previous onKill callback that was set. + Called the moment the tween is killed + + + Sets the onWaypointChange callback for the tween, clearing any previous onWaypointChange callback that was set. + Called when a path tween's current waypoint changes + + + Sets the parameters of the tween (id, ease, loops, delay, timeScale, callbacks, etc) as the parameters of the given one. + Doesn't copy specific SetOptions settings: those will need to be applied manually each time. + Has no effect if the tween has already started. + NOTE: the tween's target will not be changed + Tween from which to copy the parameters + + + Sets the parameters of the tween (id, ease, loops, delay, timeScale, callbacks, etc) as the parameters of the given TweenParams. + Has no effect if the tween has already started. + TweenParams from which to copy the parameters + + + Adds the given tween to the end of the Sequence. + Has no effect if the Sequence has already started + The tween to append + + + Adds the given tween to the beginning of the Sequence, pushing forward the other nested content. + Has no effect if the Sequence has already started + The tween to prepend + + + Inserts the given tween at the same time position of the last tween, callback or intervale added to the Sequence. + Note that, in case of a Join after an interval, the insertion time will be the time where the interval starts, not where it finishes. + Has no effect if the Sequence has already started + + + Inserts the given tween at the given time position in the Sequence, + automatically adding an interval if needed. + Has no effect if the Sequence has already started + The time position where the tween will be placed + The tween to insert + + + Adds the given interval to the end of the Sequence. + Has no effect if the Sequence has already started + The interval duration + + + Adds the given interval to the beginning of the Sequence, pushing forward the other nested content. + Has no effect if the Sequence has already started + The interval duration + + + Adds the given callback to the end of the Sequence. + Has no effect if the Sequence has already started + The callback to append + + + Adds the given callback to the beginning of the Sequence, pushing forward the other nested content. + Has no effect if the Sequence has already started + The callback to prepend + + + Inserts the given callback at the given time position in the Sequence, + automatically adding an interval if needed. + Has no effect if the Sequence has already started + The time position where the callback will be placed + The callback to insert + + + Changes a TO tween into a FROM tween: sets the current target's position as the tween's endValue + then immediately sends the target to the previously set endValue. + + + Changes a TO tween into a FROM tween: sets the current target's position as the tween's endValue + then immediately sends the target to the previously set endValue. + If TRUE the FROM value will be calculated as relative to the current one + + + Changes a TO tween into a FROM tween: sets the current value of the target as the endValue, + and the previously passed endValue as the actual startValue. + If TRUE sets the target to from value immediately, otherwise waits for the tween to start + If TRUE the FROM value will be calculated as relative to the current one + + + Changes a TO tween into a FROM tween: sets the tween's starting value to the given one + and eventually sets the tween's target to that value immediately. + Value to start from + If TRUE sets the target to from value immediately, otherwise waits for the tween to start + If TRUE the FROM/TO values will be calculated as relative to the current ones + + + Changes a TO tween into a FROM tween: sets the tween's starting value to the given one + and eventually sets the tween's target to that value immediately. + Alpha value to start from (in case of Fade tweens) + If TRUE sets the target to from value immediately, otherwise waits for the tween to start + If TRUE the FROM/TO values will be calculated as relative to the current ones + + + Changes a TO tween into a FROM tween: sets the tween's starting value to the given one + and eventually sets the tween's target to that value immediately. + Value to start from (in case of Vector tweens that act on a single coordinate or scale tweens) + If TRUE sets the target to from value immediately, otherwise waits for the tween to start + If TRUE the FROM/TO values will be calculated as relative to the current ones + + + Changes a TO tween into a FROM tween: sets the tween's starting value to the given one + and eventually sets the tween's target to that value immediately. + Value to start from (in case of Vector tweens that act on a single coordinate or scale tweens) + If TRUE sets the target to from value immediately, otherwise waits for the tween to start + If TRUE the FROM/TO values will be calculated as relative to the current ones + + + Sets a delayed startup for the tween. + In case of Sequences behaves the same as , + which means the delay will repeat in case of loops (while with tweens it's ignored after the first loop cycle). + Has no effect if the tween has already started + + + EXPERIMENTAL: implemented in v1.2.340. + Sets a delayed startup for the tween with options to choose how the delay is applied in case of Sequences. + Has no effect if the tween has already started + Only used by types: If FALSE sets the delay as a one-time occurrence + (defaults to this for types), + otherwise as a Sequence interval which will repeat at the beginning of every loop cycle + + + Sets the tween as relative + (the endValue will be calculated as startValue + endValue instead than being used directly). + Has no effect on Sequences or if the tween has already started + + + If isRelative is TRUE sets the tween as relative + (the endValue will be calculated as startValue + endValue instead than being used directly). + Has no effect on Sequences or if the tween has already started + + + If isSpeedBased is TRUE sets the tween as speed based + (the duration will represent the number of units the tween moves x second). + Has no effect on Sequences, nested tweens, or if the tween has already started + + + If isSpeedBased is TRUE sets the tween as speed based + (the duration will represent the number of units the tween moves x second). + Has no effect on Sequences, nested tweens, or if the tween has already started + + + Options for float tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector2 tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector2 tweens + Selecting an axis will tween the vector only on that axis, leaving the others untouched + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector3 tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector3 tweens + Selecting an axis will tween the vector only on that axis, leaving the others untouched + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector4 tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector4 tweens + Selecting an axis will tween the vector only on that axis, leaving the others untouched + If TRUE the tween will smoothly snap all values to integers + + + Options for Quaternion tweens + If TRUE (default) the rotation will take the shortest route, and will not rotate more than 360°. + If FALSE the rotation will be fully accounted. Is always FALSE if the tween is set as relative + + + Options for Color tweens + If TRUE only the alpha value of the color will be tweened + + + Options for Vector4 tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector4 tweens + If TRUE, rich text will be interpreted correctly while animated, + otherwise all tags will be considered as normal text + The type of scramble to use, if any + A string containing the characters to use for scrambling. + Use as many characters as possible (minimum 10) because DOTween uses a fast scramble mode which gives better results with more characters. + Leave it to NULL to use default ones + + + Options for Vector3Array tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for Vector3Array tweens + If TRUE the tween will smoothly snap all values to integers + + + Options for ShapeCircle tweens + If TRUE the center you set in the DOTween.To method will be considered as relative + to the starting position of the target + If TRUE the tween will smoothly snap all values to integers + + + Options for Path tweens (created via the DOPath shortcut) + The eventual movement axis to lock. You can input multiple axis if you separate them like this: + AxisConstrain.X | AxisConstraint.Y + The eventual rotation axis to lock. You can input multiple axis if you separate them like this: + AxisConstrain.X | AxisConstraint.Y + + + Options for Path tweens (created via the DOPath shortcut) + If TRUE the path will be automatically closed + The eventual movement axis to lock. You can input multiple axis if you separate them like this: + AxisConstrain.X | AxisConstraint.Y + The eventual rotation axis to lock. You can input multiple axis if you separate them like this: + AxisConstrain.X | AxisConstraint.Y + + + Additional LookAt options for Path tweens (created via the DOPath shortcut). + Orients the target towards the given position. + Must be chained directly to the tween creation method or to a SetOptions + The position to look at + The eventual direction to consider as "forward". + If left to NULL defaults to the regular forward side of the transform + The vector that defines in which direction up is (default: Vector3.up) + + + Additional LookAt options for Path tweens (created via the DOPath shortcut). + Orients the target towards the given position with options to keep the Z rotation stable. + Must be chained directly to the tween creation method or to a SetOptions + The position to look at + If TRUE doesn't rotate the target along the Z axis + + + Additional LookAt options for Path tweens (created via the DOPath shortcut). + Orients the target towards another transform. + Must be chained directly to the tween creation method or to a SetOptions + The transform to look at + The eventual direction to consider as "forward". + If left to NULL defaults to the regular forward side of the transform + The vector that defines in which direction up is (default: Vector3.up) + + + Additional LookAt options for Path tweens (created via the DOPath shortcut). + Orients the target towards another transform with options to keep the Z rotation stable. + Must be chained directly to the tween creation method or to a SetOptions + The transform to look at + If TRUE doesn't rotate the target along the Z axis + + + Additional LookAt options for Path tweens (created via the DOPath shortcut). + Orients the target to the path, with the given lookAhead. + Must be chained directly to the tween creation method or to a SetOptions + The percentage of lookAhead to use (0 to 1) + The eventual direction to consider as "forward". + If left to NULL defaults to the regular forward side of the transform + The vector that defines in which direction up is (default: Vector3.up) + + + Additional LookAt options for Path tweens (created via the DOPath shortcut). + Orients the path with options to keep the Z rotation stable. + Must be chained directly to the tween creation method or to a SetOptions + The percentage of lookAhead to use (0 to 1) + If TRUE doesn't rotate the target along the Z axis + + + + Types of log behaviours + + + + Log only warnings and errors + + + Log warnings, errors and additional infos + + + Log only errors + + + + Indicates either a Tweener or a Sequence + + + + TimeScale for the tween + + + If TRUE the tween will play backwards + + + If TRUE the tween is completely inverted but without playing it backwards + (play backwards will actually play the tween in the original direction) + + + Object ID (usable for filtering with DOTween static methods). Can be anything except a string or an int + (use or for those) + + + String ID (usable for filtering with DOTween static methods). 2X faster than using an object id + + + Int ID (usable for filtering with DOTween static methods). 4X faster than using an object id, 2X faster than using a string id. + Default is -999 so avoid using an ID like that or it will capture all unset intIds + + + Tween target (usable for filtering with DOTween static methods). Automatically set by tween creation shortcuts + + + Called when the tween is set in a playing state, after any eventual delay. + Also called each time the tween resumes playing from a paused state + + + Called when the tween state changes from playing to paused. + If the tween has autoKill set to FALSE, this is called also when the tween reaches completion. + + + Called when the tween is rewinded, + either by calling Rewind or by reaching the start position while playing backwards. + Rewinding a tween that is already rewinded will not fire this callback + + + Called each time the tween updates + + + Called the moment the tween completes one loop cycle + + + Called the moment the tween reaches completion (loops included) + + + Called the moment the tween is killed + + + Called when a path tween's current waypoint changes + + + Tweeners-only (ignored by Sequences), returns TRUE if the tween was set as relative + + + + Set by SetTarget if DOTween's Debug Mode is on (see DOTween Utility Panel -> "Store GameObject's ID" debug option + + + + FALSE when tween is (or should be) despawned - set only by TweenManager + + + Gets and sets the time position (loops included, delays excluded) of the tween + + + Returns TRUE if the tween is set to loop (either a set number of times or infinitely) + + + TRUE after the tween was set in a play state at least once, AFTER any delay is elapsed + + + Time position within a single loop cycle + + + + Animates a single value + + + + Changes the start value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new start value + If bigger than 0 applies it as the new tween duration + + + Changes the end value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new end value + If bigger than 0 applies it as the new tween duration + If TRUE the start value will become the current target's value, otherwise it will stay the same + + + Changes the end value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new end value + If TRUE the start value will become the current target's value, otherwise it will stay the same + + + Changes the start and end value of a tween and rewinds it (without pausing it). + Has no effect with tweens that are inside Sequences + The new start value + The new end value + If bigger than 0 applies it as the new tween duration + + + + Used internally + + + + + Update type + + + + Updates every frame during Update calls + + + Updates every frame during LateUpdate calls + + + Updates using FixedUpdate calls + + + Updates using manual update calls + + + diff --git a/DOTween.dll b/DOTween.dll new file mode 100644 index 0000000000000000000000000000000000000000..728752131941a8b5e085c63988d26c629f2bcfa2 GIT binary patch literal 175104 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 Yd_fa+v9U&t*wG}otcr_3*hOPWqGHF6 zy(`$jjtxQV6+3n;G4|ej`|g>ifie2?y7d38F7xbt=A1cmrq`#~>_4CRe0H&RB_eYHT?n=o+DnHjY$j>JwLQa6*v4SE54(H>a z7x)K)0^J?&S#{p#F^cD+up3X zq{o?+&m*Eq=sOR(c|@!;E-Vu9zWDggZ?}tk)SUiv`RPfXzZG#fT^v6aIg`}%(5PGY zO64bZj>SZ}5JRx%$`fmbph4-~Fr9whvNz)qA=rw$8j?yH=Nc z%@^8|uy-81$Pl%EbK0UD5z$c&sNkUA9{O_SCk^K89sEVx%{_lV^zneEW)vf2RzkJ+a+}(fzC;$4v`+nTc5}!DGu4tPu;x6l& zbc2My>##dU$2zTX&U_a5t>OM;GQv_TJ>g>erv>*qk`jDM2i5LWeZtQrqH{f--+SkI zKqNxru-LH9JOK)Q-v7*}OFpbOrM0C*qhq^5n{V0R`h00^-}&{P?XLY}${`Z*j*TFK z53xC&5m6l+`7AN@nQ^AqMyb|FpPOz)wnfFJgf3+-_FS$0@XMwxznM8|C~5INRDlfw z3l?8rCLq@=YqPcN-ncEr5TI~~3pY4@wXv_Qmw=eBoV{RkV_ViB~LkKuC2sy3F@ zEqfJRc!|jh-p0q``*tW^Aq3}25`i^;jdWbea(<5S(`Pmr9HcNcYz@6=i z-zaixhVx>DT7JnB7v$U?)i`|1d($H*I<8$FdxX+@`{v~CsWspI^pGCahL5%0>0aXD z#)Ofc8;3Xl>*Kad-g(`irb~n9s1BMn2G>}*{NRP}>du(6WtQ*EQqkQ5i+l&!Yb zXNS}@KbuQz?3<~H6``PYn%4eO>EWzFoa;~&mE-k_i3k7=7OB-C9|g;WjpFpo19{JirE`;RT& zThcTRb9U6UxV~}8xJp6a2hCq|d-%5K`WODw&^F-VzN!nS6kFw2$D?HIdrKP8Y0}ha zSom(r(Hh+wCE2Fd+L0vv{8hty#V-xtS!evEtZLg^4P8R4?#bm{JX?-UR2;z z?NRlkCr@tN^PqW9v*u+=4%>Mx%w<(U>yW=mr}w19k8xp6TWl2i5}GdF#X3h%DLX58 zRn>iT_IKsWok;n8@WbJ?K9{nJE|0&^Y3qB_r3vzCqxS6`Hr+1M>piL7_iVie2@@VA zmo{v*?>;cl=R|wQfbN@v*N~IDGu~TH<+^AVDcP^)5Z7N<)LY!1Z4RrR7J72k!JS{{ zR?hk+!Pn4vP|W!ErbV-eJbC2c+#8=AOaG?cvW=?`&wa9T%)$W==GVCSu=d2RACBJB z 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 literal 0 HcmV?d00001 diff --git a/DelayLoad/FullautoLauncherAnimationRiggingCompatibilityPatch.pdb b/DelayLoad/FullautoLauncherAnimationRiggingCompatibilityPatch.pdb new file mode 100644 index 0000000000000000000000000000000000000000..f462162eb3164f3a3ca3eed32745c2187ed98e18 GIT binary patch literal 9528 zcmaJ{2V7Iv_rD1d5;hJLM+TGQtzhBi~ZT~J>(OOrn{?AR`gYW|7!+Uw>-Sa)`-goc0L!6!{<{%Ej zf1YrqO2mQrp~4W`3*?ICz{7`d^-fhO@VhH;Rd9ixhmgSqp#*^TPN$4&UA76A*YXg8 zf7ClO9UXy(X#5vsxi%Rc;dcOB zz+<}%z&Z<_zJlN5@EgS8pb!ohsGOd_0>5AO;-JfLy@5;n4hMY#R}Ea3;kpA?$h#cC zF>#au#sz5n2LDZjiwBeoP4A*<9?;mIa=1D`xhq{>4KPf*11*L!CD5)wd(h?Y!#g*i zeP}upXg<)sG>u~|0J<|x_X64-=q@yUkfyr>Jq?~Q-UG^e(B%gp;Fx|7=zCCB5A}xW zK0v!e5KC$Pen7_qjeWr7{ej*O^mDKm(*uC+4zk8TIsS{bg~Q+WjPE$wxCW-!-gJUe z4idthiw40P7hC=E5Uy#2euImHZo{36a^UWQX2RY6zWq{cDMEJ1T$^M$&@N~Z+<6Ep z4&rQ=KLp-zkdKY$u#G3y#xv5!vkjhIQ2;!<*=*pW@8OLA5IC}*!`%~&fV&sk19xvI z!G9dIx>tYDHkQ*Lv`xg#4WWEeN$HK@DAlN+4v%UL3Ezf>Fzb{#q)|dp1kxx}Q?(>K zWNGM!8G55eg%ldSGB=J;l1NKr>(rE4McP;l&63b`y;?`55Lyzoyc|bp%w)3$JEf&m zQ?p4b-®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 literal 0 HcmV?d00001 diff --git a/DelayLoad/SMXMultiActionCompatibilityPatch.dll b/DelayLoad/SMXMultiActionCompatibilityPatch.dll new file mode 100644 index 0000000000000000000000000000000000000000..d0bd087bbe24bd6060f0baa0af64c9da0c85f839 GIT binary patch literal 10240 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 literal 0 HcmV?d00001 diff --git a/GearsAPI.dll b/GearsAPI.dll new file mode 100644 index 0000000000000000000000000000000000000000..d01ef8f6c154ffe494b8d54aee73ae083f023759 GIT binary patch literal 10752 zcmeHNeQX_7c0YIgzLWQG9{DiAfyoCnB;?^F&L-h&?buFY;>3>am;}rwmDm*mDpgcnKxiwKmIXn7 z=gg;Vx~*0f>L0zyoH@U9&OP_ubMKtFbD#I$a+aEiD240ekBPpIJC_cjznYwZx^($p zl<2$pmsWpY^}V!uc(Uf|Q;t317!AE@SeEVSW2Wv*TYAmXyZeXqhCOapip9dZ!1X{6 zQJ-p}QytI$By8;sTB9#gZA5Dz$@tQ*cjB(&I);m=S$NIwHwywYqH_R{b7`Vu53ni! zkM99w5z0RJ?Pul~(N{ST^UE2c#gIMKL9}DO?pI-*D3{RZfcGYF#WU~pfS+0o0-cOC z=r@oQ9lfeJu2Th)z8wR@6BPyzESC=auQ+Dih9UQr&fsES>v1JY2hpws6!u<>p9}X* zqcnY}6Mge?BE`aAqg>pk(FW8*{Ux-%OjIaj?2B=;moixfvdDpQD!YC;`1LD5Xu}$9 zeTy)}^{+sEbbkrm1H;tPk5nOZb)MWyxbDWH2<cRzd_g&N?o{ zLHIA>K80%~E)19uIv$tk*!Ch^t8sA`8S{l$$olu6fx9v+W66iwv)K%tZeqGr`+W8y zdNs@P>$RU`GV}wXPYE4wVo9seZ9<1czFzwp>SlyKB$7A8r={JL%FxyM$1?>=quB!K zXf#8w%D$w^bRqK)~AV5&k})CE0B`Mosi2P)2Qov4$FqiWwg*6ZBfjM=gSWo_Z6W zHAImu*B5+rrJy4@A5{eXFtFS%=(_>x5Ogj;J%V1%-GC@)bd#XpOZ#Y0(5?WD2)aK& zM+8{`8WVIRKof#KNcmpsq!8P~`5Q7dv@j*QT?Jp~3EE0NIxR>KygW)vX@~k84d@)n zH&v?|L$n?g^k9pJnb7F0pfA%C*-4wV+CV}2dHz&|b&;`>EpFe{xLg|&6C$O^oGMi52 zljz=D5?z^1qOZ=W_v{?YR`t6HpT9-lAUq^eX44-1QIy4JikLd|KA%V~0&uCeU((j>Xi$Y!6ftMKlHrk6&@$LM#5@>NMsaut5PUwE#bdCQW zfZy5T2Tjc}N}o?ZL&d1Q^XcNG@VHn{H442&>C4 zj4ohIAzGe)nG>6o+4OCNpC(YD@VaC=R?eo=K%C>a%%E5OLtaUj}f;XA^7}&uJWr%3!1t*LhR+55EXwPvl*kO zF`F@Z0lK!x@@42El)fxiQkz3vx|f#Xh2xjm^i@FZ3A9pei_kjgwkOa^74Cax(|2W8 zt7{|OySWVs#F3A5#lh^>SXZoOcO+07bk~Jmik;BK=$Xuo>iS6cLZ&N5=^OCQxgpZ= z+{TEb8zY|E8zW1e+X%_rem2y}+;$|;2h^EBn&Njk7k_T|_yA88w;m&IJwh_KdqYbg zP3?;i&+UN_$=t?>=Qc(>xBZbN&uxTcZU-XWlhmsQBXk~UC_-=N`xWm|xXcz?X*fVl z#P5J35t>y4>ZlqKyC#}d`_yrDI6|H34mBz$^m1E>kWo&lBsx!@i*%e(jz)+xiV>kF zQl}N~Y`ORuW!wjXPAfA)%kvx5@eoNCjuB_!7;zSk5oh5DArsxNCPFXiLg8UG8KE@L z?GbuEe^&9{kBgs)8a@zoR#_2xEBj?-N9gN#9%96qJw}|_W5k&~LPgHyG2&bvBhKZ# zALQcaaz=_aVo#vxRDy2Di&&9QuNL_;IhLFin$#xwABts6HF^QBI7KYc=nq8u0$#w1 z?oIH2DLm8ACdt?EvQy;S_n5P1KG^rid*S?U^^maHRi} z`SsiVb!S zqqzETwNM#+8GIT1#kiK?S^>NQ_dI!71uNdmUIJRc8`aA;(`KPNg?0+<6?#zU5upa? zGO7uGhtL_J_X+(o&&?`8H4e`i=E&@`BNgh1MMsuo4}8PYBYvjp`t3NMiY1f z6itF^Sm9WsbUUa<7HtEy(MOFu^iHGGbRFnD*g0u*FMSr4XFxT26g^e+7^p^H#41(v zCD6T;I>Wh!vrAa`3jt{;Du=NC78aFVD7!g!5-A@-{+eI@5qXSD3TvECMN)JyxDN&Q zcY^!7!TlGwE6f?sTNADn)=e5$2A7n+n(H0gOxN$X$EWM&jkL!!9Jh0z7g3)uy`#g% z7(`yb)8&|kXEN;FgJT?{jtWDj=kWnhV8pkETeY2fZH$IyT+eJ&y6k%0ta>%uaw~gG z%XDg0>bGu&O;o$jHpb0yNPWMd(?D#Dk00%~0%6yrVNJl+F&p+tbD^Aj++!JIb=bHG zJ{(jfbY77j$OthG42eh09L5^)y;jX*S;O=uaXZ?u$9pZ;GpwpfwUFttAUtWGFlm=L zQL_U65US4fSP+;9fn&lAqATqkFd8PomE6%uj-c>pI=pw++^M=TBXB&yce<|G7_0k= zD&}Ltc6?y5*F>wdf4c6~s)p-zn{{&nrqpFOrfPN5k!gTnywk(^-Pkl#d!}m%)NPJU zPfTzWV+&LsskyZ|vamP9H7{uzi5<*q!*EW-UWN?^Q?wf=;^rwksR--rMh8bs$HjVy zYlX@#+d5vGn05?aP7BrDrdxGtQ*)KQmS;MaQFnvh58H7?KOo|5(5xGG3g^c9u-yR% zvsd*ND!S~c8K*WenNSTF7+k007&D(_-k371gko^o@@fr}`+>H{YIQ7{xEe3!KJ&OY zV$`QiS3rrlww;FIVNwDaKc@3#o#SD0px&WVHLp6EOc;>W zYvZOfPljb)_3U|4Ja@q(PrYKF6wJ?K$wU{`@{MHFp=?mHPl$T4EIr4r2XTnRe#htJ zw6N#%g+bTniIF;OXXq1kdrU8E$MrJ^_1O~=-`=Wi4H({}ESL!J)b7G>P^J^<60jFh z>71&?X^_EQ!}Zf9_)d4ms&*Om`j}BYLDi61m{$EEB(rGv0J03txC!jPXe#6NI`vvX z6oX|%jhe+h-~q_6g5@Oq08*prbjn*rhB-$Nym$u9fG!YQ(`L&JP+G;eYiG- zq4_CwQ`gX>;Y^{M=vEM1cfVm76Q;vG@xvv)f`>-tM|{o^B%Y$!B6x~?L50^T#{(}+ zH+*ioYsQ3SyU5vY7^+YeK2j1oduqsZPS&bsR5MhE`90G6c^pq5;tq2(*jcZ4`EQL{ zB(P7J~kI~^FWvi)1HJQRbbi-d{|iQH;d z6LYH)411x4H}1b z94>GA@R=W9=Doh_v8M~w(*tjeP)b)S*QAq5gIThKVTp;B&T8d@CG6A72U9wgr8D24sZesf^{jU zhfrt8zV|a}XR;2hXi}|NXuHsLtkS`jTT7WXr7ojVwoPfcl_1p0t?0EDIc{Y`y_C^4 zP~Sig8)YYI6?9E1m&@^O@#4ksz6y4l66^9|sd~5+IXoQJ?t|r$+t|gD+qg>xvjH7o z!7!7!T=ghFSoYVLL+v>TqYRZmpc+#;?xe9hT20SUfW1rb_e5bK($2R<2uo%s5!4Kw}D{c4zSW#MEXHSiGO}n1m z(6{T|#*C|bw%%Pcbv)wksEo{~_(~i_GDIbOFGQls)c6>=opJk*F|Wrs$%TJ%;meNV zQ>nXN-*4dMFCUVoDZ2yFetZR-%pX?L*Z(rFq%r&{#+kW}c>xmtwzNRbc6)IhK1S4m z)7G$bH1Y3CBRI`C3fhCSjUnW_e*C_16!!x-{pc6d=Th%}LKw|JROF7Q{eK7ZlDzY@9DO(6$9HuJ4%Ial#bprlkEDjMfl4HrbEXs%X%-K8*@T(hZNU*wk?HpX_)1rtse$?5_#MVOJ>WLoCZ=-@YO&$NZ+#+XNeW*7fwKxJ(G$Rq5z|6wYTt-~R0Jo34Sj9Gr!Q5#~Q);xY6G?egsL7{d55;#r}@o7In3ax7aU z<^%9yV}#R)x0i^*!n)kYc8T@eI`bnwKi)f}PA7Wr%2>wG(;39$zpKaXeJZ8H|C_OM R;ZMb%N~8bZ$p4iH{3pLdcvk=b literal 0 HcmV?d00001 diff --git a/Harmony/AnimationRiggingPatches.cs b/Harmony/AnimationRiggingPatches.cs new file mode 100644 index 0000000..166f0f5 --- /dev/null +++ b/Harmony/AnimationRiggingPatches.cs @@ -0,0 +1,1731 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; +using System; +using System.Collections.Generic; +using System.Reflection.Emit; +using System.Xml.Linq; +using UniLinq; +using UnityEngine; +using UnityEngine.Animations; +using UnityEngine.Animations.Rigging; + +[HarmonyPatch] +static class AnimationRiggingPatches +{ + [HarmonyPatch(typeof(SDCSUtils), nameof(SDCSUtils.setupEquipmentCommon))] + [HarmonyPrefix] + private static bool Prefix_setupEquipmentCommon_SDCSUtils(GameObject _rigObj, out bool __state) + { + __state = false; + if (_rigObj.TryGetComponent(out var animator)) + { + __state = true; + animator.UnbindAllStreamHandles(); + animator.UnbindAllSceneHandles(); + } + return true; + } + + [HarmonyPatch(typeof(SDCSUtils), nameof(SDCSUtils.setupEquipmentCommon))] + [HarmonyPostfix] + private static void Postfix_setupEquipmentCommon_SDCSUtils(GameObject _rigObj, bool __state) + { + if (__state && _rigObj.TryGetComponent(out var animator)) + { + animator.Rebind(); + } + } + + [HarmonyPatch(typeof(SDCSUtils), nameof(SDCSUtils.setupRig))] + [HarmonyPrefix] + private static bool Prefix_setupRig_SDCSUtils(ref RuntimeAnimatorController animController, ref GameObject _rigObj) + { + if (_rigObj && _rigObj.TryGetComponent(out var builder) && builder.HasWeaponOverride) + { + animController = null; + } + return true; + } + + //[HarmonyPatch(typeof(UMACharacterBodyAnimator), nameof(UMACharacterBodyAnimator.assignLayerWeights))] + //[HarmonyPrefix] + //private static bool Prefix_assignLayerWeights_UMACharacterBodyAnimator(UMACharacterBodyAnimator __instance) + //{ + // if (__instance.Animator && __instance.Animator.TryGetComponent(out var builder) && builder.HasWeaponOverride) + // { + // return false; + // } + // return true; + //} + + //[HarmonyPatch(typeof(AvatarSDCSController), nameof(AvatarSDCSController.setLayerWeights))] + //[HarmonyPrefix] + //private static bool Prefix_setLayerWeights_AvatarSDCSController(AvatarSDCSController __instance) + //{ + // if (__instance.anim && __instance.anim.TryGetComponent(out var builder) && builder.HasWeaponOverride) + // { + // return false; + // } + // return true; + //} + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.OnModificationsChanged))] + [HarmonyPostfix] + private static void Postfix_OnModificationChanged_ItemActionRanged(ItemActionData _data) + { + ItemActionRanged.ItemActionDataRanged rangedData = (ItemActionRanged.ItemActionDataRanged)_data; + if (rangedData.IsDoubleBarrel) + { + rangedData.muzzle = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, "Muzzle_L"); + rangedData.muzzle2 = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, "Muzzle_R"); + } + else + { + rangedData.muzzle = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, "Muzzle"); + } + rangedData.Laser = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, "laser"); + + ItemActionLauncher.ItemActionDataLauncher launcherData = _data as ItemActionLauncher.ItemActionDataLauncher; + if (launcherData != null) + { + launcherData.projectileJoint = AnimationRiggingManager.GetTransformOverrideByName(launcherData.invData.model, "ProjectileJoint"); + } + } + + + /// + /// attachment path patch, only apply to MinEventActionSetTransformActive! + /// + /// + /// + [HarmonyPatch(typeof(MinEventActionSetTransformActive), nameof(MinEventActionSetTransformActive.Execute))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_Execute_MinEventActionSetTransformActive(IEnumerable instructions) + { + var codes = instructions.ToList(); + var mtd_find = AccessTools.Method(typeof(GameUtils), nameof(GameUtils.FindDeepChild)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_find)) + { + codes.RemoveAt(i); + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.Self)), + CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetAttachmentReferenceOverrideTransform)) + }); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(MinEventActionSetTransformChildrenActive), nameof(MinEventActionSetTransformChildrenActive.Execute))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_Execute_MinEventActionSetTransformChildrenActive(IEnumerable instructions) + { + var codes = instructions.ToList(); + var mtd_find = AccessTools.Method(typeof(GameUtils), nameof(GameUtils.FindDeepChildActive)); + var fld_trans = AccessTools.Field(typeof(MinEventActionSetTransformChildrenActive), nameof(MinEventActionSetTransformChildrenActive.transformPath)); + for (int i = 1; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_find) && codes[i - 1].LoadsField(fld_trans)) + { + codes.RemoveAt(i); + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.Self)), + CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetAttachmentReferenceOverrideTransformActive)) + }); + break; + } + } + return codes; + } + + [HarmonyPatch(typeof(MinEventActionAddPart), nameof(MinEventActionAddPart.Execute))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_Execute_MinEventActionAddPart(IEnumerable instructions) + { + var codes = instructions.ToList(); + var mtd_idx = AccessTools.PropertyGetter(typeof(Inventory), nameof(Inventory.holdingItemIdx)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_idx)) + { + codes.InsertRange(i + 2, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(MinEventActionAddPart),nameof(MinEventActionAddPart.partName)), + new CodeInstruction(OpCodes.Ldc_I4_1), + CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetAddPartTransformOverride)) + }); + break; + } + } + return codes; + } + + [HarmonyPatch(typeof(MinEventActionAttachPrefabToHeldItem), nameof(MinEventActionAttachPrefabToHeldItem.Execute))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_Execute_MinEventActionAttachPrefabToHeldItem(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + var mtd_find = AccessTools.Method(typeof(GameUtils), nameof(GameUtils.FindDeepChild)); + var fld_trans = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.Transform)); + var mtd_layer = AccessTools.Method(typeof(Utils), nameof(Utils.SetLayerRecursively)); + + var lbd_targets = generator.DeclareLocal(typeof(AnimationTargetsAbs)); + + for (int i = 1; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Stloc_0) + { + if (codes[i - 1].Calls(mtd_find)) + { + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldc_I4_0), + CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetAddPartTransformOverride)) + }); + codes.RemoveAt(i - 1); + i += 1; + } + else if (codes[i - 1].LoadsField(fld_trans)) + { + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(MinEventActionAttachPrefabToHeldItem), nameof(MinEventActionAttachPrefabToHeldItem.parent_transform)), + new CodeInstruction(OpCodes.Ldc_I4_0), + CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetAddPartTransformOverride)) + }); + i += 4; + } + } + else if (codes[i].opcode == OpCodes.Stloc_2) + { + var lbl = generator.DefineLabel(); + var lbls = codes[i + 1].ExtractLabels(); + codes[i + 1].WithLabels(lbl); + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_1).WithLabels(lbls), + CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.Transform)), + new CodeInstruction(OpCodes.Ldnull), + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(UnityEngine.Object), "op_Inequality")), + new CodeInstruction(OpCodes.Brfalse_S, lbl), + new CodeInstruction(OpCodes.Ldarg_1), + CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.Transform)), + CodeInstruction.Call(typeof(Transform), nameof(Transform.GetComponent), new Type[0], new Type[]{ typeof(AnimationTargetsAbs)}), + new CodeInstruction(OpCodes.Stloc_S, lbd_targets) + }); + i += 9; + } + else if (codes[i].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 4) + { + codes.RemoveAt(i - 1); + codes.InsertRange(i - 1, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_targets), + new CodeInstruction(OpCodes.Ldloc_2), + CodeInstruction.Call(typeof(AnimationRiggingPatches), nameof(CreateOrMoveAttachment)) + }); + i += 2; + } + else if (codes[i].Calls(mtd_layer)) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_targets), + new CodeInstruction(OpCodes.Ldloc_S, 4), + CodeInstruction.Call(typeof(AnimationRiggingPatches), nameof(CheckAttachmentRefMerge)) + }); + i += 3; + } + else if (codes[i].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 5) + { + var lbl = generator.DefineLabel(); + var lbls = codes[i + 1].ExtractLabels(); + codes[i + 1].WithLabels(lbl); + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldloc_3).WithLabels(lbls), + CodeInstruction.Call(typeof(Transform), nameof(Transform.GetComponent), new Type[0], new Type[]{ typeof(IgnoreTint)}), + new CodeInstruction(OpCodes.Ldnull), + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(UnityEngine.Object), "op_Inequality")), + new CodeInstruction(OpCodes.Brfalse_S, lbl), + new CodeInstruction(OpCodes.Ret) + }); + i += 6; + } + } + codes.InsertRange(0, new[] + { + new CodeInstruction(OpCodes.Ldnull), + new CodeInstruction(OpCodes.Stloc_S, lbd_targets) + }); + return codes; + } + + private static GameObject CreateOrMoveAttachment(GameObject go, AnimationTargetsAbs targets, string name) + { + GameObject res = null; + if (targets) + { + res = targets.GetPrefab(name); + } + if (!res) + { + res = GameObject.Instantiate(go); + } + return res; + } + + private static void CheckAttachmentRefMerge(AnimationTargetsAbs targets, GameObject attachmentReference) + { + if (targets) + { + targets.AttachPrefab(attachmentReference); + } + } + + /// + /// reload logging patch + /// + /// + [HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateEnter))] + [HarmonyPostfix] + private static void Postfix_OnStateEnter_AnimatorRangedReloadState(AnimatorStateInfo stateInfo) + { + if (ConsoleCmdReloadLog.LogInfo) + { + Log.Out(string.Format("ANIMATION LENGTH: length {0} speed {1} speedMultiplier {2} original length {3}", stateInfo.length, stateInfo.speed, stateInfo.speedMultiplier, stateInfo.length * stateInfo.speedMultiplier)); + } + } + + [HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.OnHoldingItemChanged))] + [HarmonyPostfix] + private static void Postfix_OnHoldingItemChanged_EntityAlive(EntityAlive __instance) + { + AnimationRiggingManager.OnHoldingItemIndexChanged(__instance as EntityPlayer); + } + + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.OnHoldingItemChanged))] + [HarmonyPostfix] + private static void Postfix_OnHoldingItemChanged_EntityPlayerLocal(EntityPlayerLocal __instance) + { + AnimationRiggingManager.OnHoldingItemIndexChanged(__instance); + } + + [HarmonyPatch(typeof(GameManager), nameof(GameManager.SaveAndCleanupWorld))] + [HarmonyPostfix] + private static void Postfix_SaveAndCleanupWorld_GameManager() + { + AnimationRiggingManager.Clear(); + } + + private static void ParseTakeOverReloadTime(XElement _node) + { + string itemName = _node.GetAttribute("name"); + if (string.IsNullOrEmpty(itemName)) + { + return; + } + ItemClass item = ItemClass.GetItemClass(itemName); + if (item.Properties.GetBool("TakeOverReloadTime")) + { + AnimationRiggingManager.AddReloadTimeTakeOverItem(item.Name); + //Log.Out($"take over reload time: {item.Name} {item.Id}"); + } + } + + [HarmonyPatch(typeof(ItemClassesFromXml), nameof(ItemClassesFromXml.parseItem))] + [HarmonyPostfix] + private static void Postfix_parseItem_ItemClassesFromXml(XElement _node) + { + ParseTakeOverReloadTime(_node); + } + + //[HarmonyPatch(typeof(ItemClass), nameof(ItemClass.StopHolding))] + //[HarmonyPostfix] + //private static void Postfix_StopHolding_ItemClass(Transform _modelTransform) + //{ + // if (_modelTransform != null && _modelTransform.TryGetComponent(out var targets) && !targets.Destroyed) + // { + // targets.SetEnabled(false); + // } + //} + + [HarmonyPatch(typeof(Inventory), nameof(Inventory.createHeldItem))] + [HarmonyPostfix] + private static void Postfix_createHeldItem_Inventory(Inventory __instance, Transform __result) + { + if (__result && __result.TryGetComponent(out var targets) && !targets.Destroyed) + { + if (GameManager.IsDedicatedServer || !(__instance.entity is EntityPlayer player)) + { + targets.Destroy(); + } + else + { + if (player is EntityPlayerLocal localPlayer) + { + targets.Init(localPlayer.emodel.avatarController.GetActiveModelRoot(), localPlayer.bFirstPersonView); + } + else + { + targets.DestroyFpv(); + targets.Init(player.emodel.avatarController.GetActiveModelRoot(), false); + } + } + } + } + + [HarmonyPatch(typeof(Inventory), nameof(Inventory.ForceHoldingItemUpdate))] + [HarmonyPrefix] + private static bool Prefix_ForceHoldingItemUpdate(Inventory __instance) + { + if (__instance.entity is EntityPlayer) + AnimationRiggingManager.OnClearInventorySlot(__instance, __instance.holdingItemIdx); + return true; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ItemActionEffects))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ItemActionEffects_ItemActionRanged(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + var fld_fpv = AccessTools.Field(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.bFirstPersonView)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_fpv)) + { + codes.InsertRange(i + 4, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, codes[i + 3].operand), + new CodeInstruction(OpCodes.Ldarg_2), + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.particlesMuzzleFire))), + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.particlesMuzzleFireFpv))), + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.particlesMuzzleSmoke))), + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.particlesMuzzleSmokeFpv))), + new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.SpawnFpvParticles))), + new CodeInstruction(OpCodes.Brtrue_S, codes[i - 5].operand) + }); + break; + } + } + //FieldInfo fld_muzzle = AccessTools.Field(typeof(ItemActionRanged.ItemActionDataRanged), nameof(ItemActionRanged.ItemActionDataRanged.muzzle)); + //FieldInfo fld_muzzle2 = AccessTools.Field(typeof(ItemActionRanged.ItemActionDataRanged), nameof(ItemActionRanged.ItemActionDataRanged.muzzle2)); + //MethodInfo mtd_getmuzzle = AccessTools.Method(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetMuzzleOverrideFPV)); + //MethodInfo mtd_getmuzzle2 = AccessTools.Method(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetMuzzle2OverrideFPV)); + //for (int i = 0; i < codes.Count; i++) + //{ + // if (codes[i].LoadsField(fld_muzzle)) + // { + // codes.InsertRange(i + 1, new[] + // { + // new CodeInstruction(OpCodes.Ldloc_S, 4), + // new CodeInstruction(OpCodes.Call, mtd_getmuzzle) + // }); + // } + // else if (codes[i].LoadsField(fld_muzzle2)) + // { + // codes.InsertRange(i + 1, new[] + // { + // new CodeInstruction(OpCodes.Ldloc_S, 4), + // new CodeInstruction(OpCodes.Call, mtd_getmuzzle2) + // }); + // } + //} + + return codes; + } + + [HarmonyPatch(typeof(Inventory), nameof(Inventory.clearSlotByIndex))] + [HarmonyPrefix] + private static bool Prefix_clearSlotByIndex(Inventory __instance, int _idx) + { + if (__instance.entity is EntityPlayer) + AnimationRiggingManager.OnClearInventorySlot(__instance, _idx); + return true; + } + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.Update))] + [HarmonyPostfix] + private static void Postfix_Update_AvatarMultiBodyController(AvatarMultiBodyController __instance) + { + AnimationRiggingManager.UpdatePlayerAvatar(__instance); + if (__instance is AvatarLocalPlayerController avatarLocalPlayer) + { + //if ((avatarLocalPlayer.entity as EntityPlayerLocal).bFirstPersonView && !avatarLocalPlayer.entity.inventory.GetIsFinishedSwitchingHeldItem()) + //{ + // avatarLocalPlayer.UpdateInt(AvatarController.weaponHoldTypeHash, -1, false); + // avatarLocalPlayer.UpdateBool("Holstered", false, false); + // avatarLocalPlayer.FPSArms.Animator.Play("idle", 0, 0f); + //} + var mapping = MultiActionManager.GetMappingForEntity(__instance.entity.entityId); + if (mapping != null) + { + avatarLocalPlayer.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, mapping.CurActionIndex, true); + } + + if (__instance.entity.inventory?.holdingItemData?.actionData != null) + { + foreach (var actionData in __instance.entity.inventory.holdingItemData.actionData) + { + if (actionData is IModuleContainerFor data) + { + avatarLocalPlayer.UpdateInt(ActionModuleFireModeSelector.FireModeParamHashes[actionData.indexInEntityOfAction], data.Instance.currentFireMode, true); + } + } + } + } + if (__instance.entity.AttachedToEntity) + { + __instance.SetVehicleAnimation(AvatarController.vehiclePoseHash, __instance.entity.vehiclePoseMode); + } + } + + [HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController.Update))] + [HarmonyPostfix] + private static void Postfix_Update_LegacyAvatarController(LegacyAvatarController __instance) + { + AnimationRiggingManager.UpdatePlayerAvatar(__instance); + if (__instance.entity && __instance.entity.AttachedToEntity) + { + __instance.SetVehicleAnimation(AvatarController.vehiclePoseHash, __instance.entity.vehiclePoseMode); + } + } + + //[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController.LateUpdate))] + //[HarmonyPostfix] + //private static void Postfix_LateUpdate_AvatarLocalPlayerController(AvatarLocalPlayerController __instance) + //{ + // var targets = AnimationRiggingManager.GetRigTargetsFromPlayer(__instance.entity as EntityPlayer); + // if (targets && !targets.Destroyed) + // { + // targets.UpdateTpvSpineRotation(__instance.entity as EntityPlayer); + // } + //} + + //[HarmonyPatch(typeof(AvatarSDCSController), nameof(AvatarSDCSController.LateUpdate))] + //[HarmonyPostfix] + //private static void Postfix_LateUpdate_AvatarSDCSController(AvatarSDCSController __instance) + //{ + // var targets = AnimationRiggingManager.GetRigTargetsFromPlayer(__instance.entity as EntityPlayer); + // if (targets && !targets.Destroyed) + // { + // targets.UpdateTpvSpineRotation(__instance.entity as EntityPlayer); + // } + //} + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.StartAnimationReloading))] + [HarmonyPrefix] + private static bool Prefix_StartAnimationReloding_AvatarController(AvatarMultiBodyController __instance) + { + __instance.Entity?.FireEvent(CustomEnums.onReloadAboutToStart); + return true; + } + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.StartAnimationReloading))] + [HarmonyPostfix] + private static void Postfix_StartAnimationReloading_AvatarMultibodyController(AvatarMultiBodyController __instance) + { + if (__instance.HeldItemTransform != null && __instance.HeldItemTransform.TryGetComponent(out var targets) && !targets.Destroyed) + { + EntityAlive entity = __instance.Entity; + ItemValue holdingItemItemValue = entity.inventory.holdingItemItemValue; +//#if DEBUG +// float x = 1, y = 1; +// var tags = entity.inventory.holdingItem.ItemTags; +// var tags_prev = tags; +// MultiActionManager.ModifyItemTags(entity.inventory.holdingItemItemValue, entity.MinEventContext.ItemActionData, ref tags); +// entity.Progression.ModifyValue(PassiveEffects.ReloadSpeedMultiplier, ref x, ref y, tags); +// Log.Out($"item {entity.inventory.holdingItem.Name} action index {entity.MinEventContext.ItemActionData.indexInEntityOfAction} progression base {x} perc {y} has tag {tags.Test_AnySet(FastTags.Parse("perkMachineGunner"))} \ntags prev {tags_prev} \ntags after {tags}"); +//#endif + float reloadSpeed = EffectManager.GetValue(PassiveEffects.ReloadSpeedMultiplier, holdingItemItemValue, 1f, entity); + float reloadSpeedRatio = EffectManager.GetValue(CustomEnums.ReloadSpeedRatioFPV2TPV, holdingItemItemValue, 1f, entity); + + float partialReloadMultiplier = EffectManager.GetValue(CustomEnums.PartialReloadCount, holdingItemItemValue, 0, entity); + float partialReloadRatio = 1f; + if (partialReloadMultiplier <= 0) + { + partialReloadMultiplier = 1; + } + else + { + int magSize = (int)EffectManager.GetValue(PassiveEffects.MagazineSize, holdingItemItemValue, ((ItemActionRanged)entity.inventory.holdingItem.Actions[MultiActionManager.GetActionIndexForEntity(entity)]).BulletsPerMagazine, entity); + //how many partial reload is required to fill an empty mag + partialReloadRatio = Mathf.Ceil(magSize / partialReloadMultiplier); + //how many partial reload is required to finish this reload + partialReloadMultiplier = Mathf.Ceil((magSize - holdingItemItemValue.Meta) / partialReloadMultiplier); + //reload time percentage of this reload + partialReloadRatio = partialReloadMultiplier / partialReloadRatio; + } + + float localMultiplier, remoteMultiplier; + bool isFPV = entity as EntityPlayerLocal != null && (entity as EntityPlayerLocal).emodel.IsFPV; + bool takeOverReloadTime = AnimationRiggingManager.IsReloadTimeTakeOverItem(holdingItemItemValue.type); + + if (isFPV && !takeOverReloadTime) + { + localMultiplier = reloadSpeed / reloadSpeedRatio; + } + else if (!isFPV && takeOverReloadTime) + { + localMultiplier = reloadSpeed * reloadSpeedRatio / partialReloadMultiplier; + } + else if(isFPV && takeOverReloadTime) + { + localMultiplier = reloadSpeed; + } + else + { + localMultiplier = reloadSpeed * partialReloadRatio; + } + + if (takeOverReloadTime) + { + remoteMultiplier = reloadSpeed * reloadSpeedRatio / partialReloadMultiplier; + } + else + { + remoteMultiplier = reloadSpeed * partialReloadRatio; + } + + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"Set reload multiplier: isFPV {isFPV}, reloadSpeed {reloadSpeed}, reloadSpeedRatio {reloadSpeedRatio}, finalMultiplier {localMultiplier}, remoteMultiplier {remoteMultiplier}, partialMultiplier {partialReloadMultiplier}, partialRatio {partialReloadRatio}"); + + __instance.UpdateFloat(AvatarController.reloadSpeedHash, localMultiplier, false); + SetDataFloat(__instance, (AvatarController.DataTypes)AvatarController.reloadSpeedHash, remoteMultiplier, true); + } + } + + /// + /// sets float only on remote clients but not on local client. + /// + /// + /// + /// + /// + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController.SetDataFloat))] + [HarmonyReversePatch(HarmonyReversePatchType.Original)] + private static void SetDataFloat(AvatarController __instance, AvatarController.DataTypes _type, float _value, bool _netsync = true) + { + IEnumerable Transpiler(IEnumerable instructions) + { + if (instructions == null) + return null; + + var codes = instructions.ToList(); + codes.RemoveRange(0, 5); + codes[0].labels.Clear(); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsConstant(AnimParamData.ValueTypes.DataFloat)) + { + codes[i].opcode = OpCodes.Ldc_I4; + codes[i].operand = (int)AnimParamData.ValueTypes.Float; + break; + } + } + return codes; + } + _ = Transpiler(null); + } + + //[HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.StartAnimationAttack))] + //[HarmonyPostfix] + //private static void Postfix_StartAnimationAttack_AvatarMultiBodyController(AvatarMultiBodyController __instance) + //{ + // if (__instance is AvatarLocalPlayerController) + // AnimationRiggingManager.FpvWeaponFire(); + //} + + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.SetFirstPersonView))] + [HarmonyPrefix] + private static bool Prefix_SetFirstPersonView_EntityPlayerLocal(EntityPlayerLocal __instance, bool _bFirstPersonView) + { + var targets = AnimationRiggingManager.GetRigTargetsFromPlayer(__instance); + if (_bFirstPersonView != __instance.bFirstPersonView && targets && !targets.Destroyed && targets.IsAnimationSet) + { + //targets.SetEnabled(false); + //targets.GraphBuilder.SetCurrentTarget(null); + Log.Out($"Switch view destroy slot {__instance.inventory.holdingItemIdx}"); + targets.Destroy(); + } + return true; + } + + [HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController.SwitchModelAndView))] + [HarmonyPostfix] + private static void Postfix_SwitchModelAndView_AvatarLocalPlayerController(AvatarLocalPlayerController __instance, bool _bFPV) + { + if (_bFPV) + { + __instance.hasTurnRate = false; + } + } + + [HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController.SetInRightHand))] + [HarmonyPostfix] + private static void Postfix_SetInRightHand_AvatarLocalPlayerController(Transform _transform, AvatarLocalPlayerController __instance) + { + if (_transform != null && _transform.TryGetComponent(out var targets) && !targets.Destroyed && targets.ItemCurrent) + { + //targets.SetEnabled(true); + targets.GraphBuilder.SetCurrentTarget(targets); + } + else if (__instance.PrimaryBody?.Animator && __instance.PrimaryBody.Animator.TryGetComponent(out var builder)) + { + builder.SetCurrentTarget(null); + } + } + + [HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController.SetInRightHand))] + [HarmonyPostfix] + private static void Postfix_SetInRightHand_LegacyAvatarController(Transform _transform, LegacyAvatarController __instance) + { + if (_transform != null && _transform.TryGetComponent(out var targets) && !targets.Destroyed && targets.ItemCurrent) + { + //targets.SetEnabled(true); + targets.GraphBuilder.SetCurrentTarget(targets); + } + else if (__instance.anim && __instance.anim.TryGetComponent(out var builder)) + { + builder.SetCurrentTarget(null); + } + } + + //[HarmonyPatch(typeof(Inventory), nameof(Inventory.setHoldingItemTransform))] + //[HarmonyPrefix] + //private static bool Prefix_setHoldingItemTransform_Inventory(Inventory __instance) + //{ + // if (__instance.lastdrawnHoldingItemTransform && __instance.lastdrawnHoldingItemTransform.TryGetComponent(out var targets) && !targets.Destroyed) + // { + // targets.SetEnabled(false); + // } + // return true; + //} + + [HarmonyPatch(typeof(vp_FPWeapon), nameof(vp_FPWeapon.Start))] + [HarmonyPostfix] + private static void Postfix_Start_vp_FPWeapon(vp_FPWeapon __instance) + { + var player = __instance.GetComponentInParent(); + if (player && player.inventory != null) + { + for (int i = 0; i < player.inventory.models.Length; i++) + { + Transform model = player.inventory.models[i]; + if (model != null && model.TryGetComponent(out var targets) && !targets.Destroyed) + { + if (i == player.inventory.holdingItemIdx) + { + player.inventory.ForceHoldingItemUpdate(); + } + else + { + targets.Init(__instance.transform, true); + } + } + } + } + } + + #region temporary fix for arm glitch on switching weapon + [HarmonyPatch(typeof(Inventory), nameof(Inventory.updateHoldingItem))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_updateHoldingItem_Inventory(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_setparent = AccessTools.Method(typeof(Transform), nameof(Transform.SetParent), new[] { typeof(Transform), typeof(bool) }); + var mtd_startholding = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.StartHolding)); + var mtd_showrighthand = AccessTools.Method(typeof(Inventory), nameof(Inventory.ShowRightHand)); + var mtd_holdingchanged = AccessTools.Method(typeof(EntityAlive), nameof(EntityAlive.OnHoldingItemChanged)); + var prop_holdingitem = AccessTools.PropertyGetter(typeof(Inventory), nameof(Inventory.holdingItem)); + var fld_transform = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.Transform)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_setparent)) + { + codes[i - 1].opcode = OpCodes.Ldc_I4_1; + } + else if (codes[i].Calls(mtd_startholding)) + { + for (int j = i - 1; j >= 0; j--) + { + if (codes[j].Calls(prop_holdingitem)) + { + for (int k = i + 1; k < codes.Count; k++) + { + if (codes[k].StoresField(fld_transform)) + { + codes.InsertRange(k + 1, new[] + { + new CodeInstruction(OpCodes.Ldloc_0).WithLabels(codes[k + 1].ExtractLabels()), + CodeInstruction.LoadField(typeof(CustomEnums), nameof(CustomEnums.onSelfHoldingItemAssemble)), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(Inventory), nameof(Inventory.entity)), + CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)), + CodeInstruction.Call(typeof(ItemValue), nameof(ItemValue.FireEvent)), + }); + k += 6; + } + else if (codes[k].Calls(mtd_showrighthand)) + { + codes.InsertRange(k + 1, codes.GetRange(j - 1, i - j + 2)); + codes[i + 1].WithLabels(codes[j - 1].ExtractLabels()); + codes.RemoveRange(j - 1, i - j + 2); + break; + } + } + break; + } + } + i += 6; + } + else if (codes[i].Calls(mtd_holdingchanged)) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0).WithLabels(codes[i + 1].ExtractLabels()), + CodeInstruction.Call(typeof(Inventory), nameof(Inventory.syncHeldItem)) + }); + break; + } + } + return codes; + } + + [HarmonyPatch(typeof(Inventory), nameof(Inventory.setHoldingItemTransform))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setHoldingItemTransform_Inventory(IEnumerable instructions) + { + var codes = instructions.ToList(); + var mtd_sync = AccessTools.Method(typeof(Inventory), nameof(Inventory.syncHeldItem)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_sync)) + { + codes[i + 1].WithLabels(codes[i - 1].ExtractLabels()); + codes.RemoveRange(i - 1, 2); + break; + } + } + return codes; + } + + + //private static Coroutine delayShowWeaponCo; + //private static IEnumerator DelayShowWeapon(Camera camera) + //{ + // Log.Out($"Delay show weapon!"); + // camera.cullingMask &= ~(1 << 10); + // yield return new WaitForSeconds(0.5f); + // if (camera) + // { + // camera.cullingMask |= 1 << 10; + // } + // delayShowWeaponCo = null; + // Log.Out($"Show weapon!"); + // yield break; + //} + + //[HarmonyPatch(typeof(Inventory), nameof(Inventory.setHeldItemByIndex))] + //[HarmonyPrefix] + //private static bool Prefix_setHeldItemByIndex_Inventory(Inventory __instance, out bool __state) + //{ + // __state = __instance.holdingItemData?.model && __instance.holdingItemData.model.GetComponent(); + + // return true; + //} + + //[HarmonyPatch(typeof(Inventory), nameof(Inventory.setHeldItemByIndex))] + //[HarmonyPostfix] + //private static void Postfix_setHeldItemByIndex_Inventory(Inventory __instance, bool __state) + //{ + // if (__state && __instance.entity is EntityPlayerLocal player && player.bFirstPersonView && (!__instance.holdingItemData?.model || !__instance.holdingItemData.model.GetComponent())) + // { + // if (delayShowWeaponCo != null) + // { + // ThreadManager.StopCoroutine(delayShowWeaponCo); + // } + + // if (__instance.holdingItemIdx == __instance.DUMMY_SLOT_IDX) + // { + // player.ShowHoldingItem(true); + // } + // else + // { + // delayShowWeaponCo = ThreadManager.StartCoroutine(DelayShowWeapon(player.playerCamera)); + // } + // } + //} + + //[HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.ShowHoldingItem))] + //[HarmonyPrefix] + //private static bool Prefix_ShowHoldingItem_EntityPlayerLocal(bool show) + //{ + // if (delayShowWeaponCo != null) + // { + // if (show) + // { + // return false; + // } + // ThreadManager.StopCoroutine(delayShowWeaponCo); + // } + // return true; + //} + /* + [HarmonyPatch(typeof(Inventory), nameof(Inventory.setHoldingItemTransform))] + [HarmonyPostfix] + private static void Postfix_setHoldingItemTransform_Inventory(Transform _t, Inventory __instance) + { + if (_t != null && _t.TryGetComponent(out var targets) && !targets.Destroyed) + { + targets.SetEnabled(__instance.entity.emodel.IsFPV); + } + } + + [HarmonyPatch(typeof(Inventory), nameof(Inventory.SetItem), new[] {typeof(int), typeof(ItemValue), typeof(int), typeof(bool)})] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SetItem_Inventory(IEnumerable instructions) + { + MethodInfo mtd_update = AccessTools.Method(typeof(Inventory), nameof(Inventory.updateHoldingItem)); + foreach (var code in instructions) + { + yield return code; + if (code.Calls(mtd_update)) + { + yield return new CodeInstruction(OpCodes.Ldarg_0); + yield return new CodeInstruction(OpCodes.Ldc_I4_1); + yield return new CodeInstruction(OpCodes.Ldc_R4, 0f); + yield return CodeInstruction.Call(typeof(Inventory), nameof(Inventory.ShowHeldItem)); + } + } + } + + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.ShowWeaponCamera))] + [HarmonyPostfix] + private static void Postfix_ShowWeaponCamera_EntityPlayerLocal(EntityPlayerLocal __instance, bool show) + { + if (__instance.bFirstPersonView) + { + __instance.weaponCamera.cullingMask &= ~(1 << 10); + if (delayShowWeaponCo != null) + { + ThreadManager.StopCoroutine(delayShowWeaponCo); + } + if (show) + { + delayShowWeaponCo = ThreadManager.StartCoroutine(DelayShowWeapon(__instance.weaponCamera)); + } + } + } + + */ + #endregion + + [HarmonyPatch(typeof(World), nameof(World.SpawnEntityInWorld))] + [HarmonyPrefix] + private static bool Prefix_SpawnEntityInWorld_World(Entity _entity) + { + if (_entity is EntityItem _entityItem) + { + var targets = _entityItem.GetComponentInChildren(true); + if (targets && !targets.Destroyed) + { + targets.Destroy(); + } + } + return true; + } + + [HarmonyPatch(typeof(World), nameof(World.SpawnEntityInWorld))] + [HarmonyPostfix] + private static void Postfix_SpawnEntityInWorld_World(Entity _entity) + { + if (_entity is EntityPlayer player && !(_entity is EntityPlayerLocal) && player.inventory != null) + { + foreach (var model in player.inventory.models) + { + if (model && model.TryGetComponent(out var targets) && !targets.Destroyed) + { + targets.DestroyFpv(); + targets.Init(player.emodel.avatarController.GetActiveModelRoot(), false); + } + } + } + } + + [HarmonyPatch(typeof(EntityItem), nameof(EntityItem.createMesh))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_createMesh_EntityItem(IEnumerable instructions) + { + var codes = instructions.ToList(); + codes[codes.Count - 1].WithLabels(codes[codes.Count - 11].labels); + codes.RemoveRange(codes.Count - 11, 10); + return codes; + } + + [HarmonyPatch(typeof(EntityItem), nameof(EntityItem.createMesh))] + [HarmonyPostfix] + private static void Postfix_createMesh_EntityItem(EntityItem __instance) + { + if (__instance.itemTransform) + { + __instance.itemTransform.tag = "Item"; + if (__instance.itemTransform.TryGetComponent(out var targets) && !targets.Destroyed) + { + targets.Destroy(); + } + } + __instance.meshRenderers = __instance.itemTransform.GetComponentsInChildren(true); + __instance.VisiblityCheck(0, false); + } + + [HarmonyPatch(typeof(EModelBase), nameof(EModelBase.SwitchModelAndView))] + [HarmonyPostfix] + private static void Postfix_SwitchModelAndView_EModelBase(EModelBase __instance) + { + if (__instance.entity is EntityPlayerLocal player && player.inventory != null) + { + foreach (var model in player.inventory.models) + { + if (model && model.TryGetComponent(out var targets) && !targets.Destroyed) + { + targets.Init(player.emodel.avatarController.GetActiveModelRoot(), player.bFirstPersonView); + } + } + } + } + + [HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.Detach))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_Detach_EntityAlive(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var fld_inv = AccessTools.Field(typeof(EntityAlive), nameof(EntityAlive.inventory)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].StoresField(fld_inv)) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.Call(typeof(AnimationRiggingPatches), nameof(AnimationRiggingPatches.DetachInitInventory)) + }); + break; + } + } + return codes; + } + + private static void DetachInitInventory(EntityAlive __instance) + { + if (!(__instance is EntityPlayer player)) + { + return; + } + if (__instance.inventory != null) + { + foreach (var model in __instance.inventory.models) + { + if (model && model.TryGetComponent(out var targets) && !targets.Destroyed) + { + targets.Init(__instance.emodel.avatarController.GetActiveModelRoot(), player is EntityPlayerLocal localPlayer ? localPlayer.bFirstPersonView : false); + } + } + } + } + + [HarmonyPatch(typeof(SDCSUtils), nameof(SDCSUtils.cleanupEquipment))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_cleanupEquipment_SDCSUtils(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_removeat = AccessTools.Method(typeof(List), nameof(List.RemoveAt)); + var mtd_destroy = AccessTools.Method(typeof(GameUtils), nameof(GameUtils.DestroyAllChildrenBut), new[] {typeof(Transform), typeof(List)}); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_removeat)) + { + codes.InsertRange(i - 2, new[] + { + new CodeInstruction(OpCodes.Ldloc_2), + new CodeInstruction(OpCodes.Ldloc_3), + CodeInstruction.Call(typeof(List), "get_Item"), + CodeInstruction.Call(typeof(RigLayer), "get_name"), + CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.ShouldExcludeRig)), + new CodeInstruction(OpCodes.Brtrue_S, codes[i - 3].operand) + }); + i += 6; + } + else if (codes[i].Calls(mtd_destroy)) + { + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Dup), + CodeInstruction.Call(typeof(AnimationRiggingManager), nameof(AnimationRiggingManager.GetExcludeRigs)), + CodeInstruction.Call(typeof(List), nameof(List.AddRange)), + }); + i += 3; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.SwapSelectedAmmo))] + [HarmonyPrefix] + private static bool Prefix_SwapSelectedAmmo_ItemActionRanged(ItemActionRanged __instance, EntityAlive _entity, int _ammoIndex) + { + if (_ammoIndex == (int)_entity.inventory.holdingItemItemValue.SelectedAmmoTypeIndex && __instance is IModuleContainerFor inspectable && _entity is EntityPlayerLocal player) + { + ItemActionRanged.ItemActionDataRanged _actionData = _entity.inventory.holdingItemData.actionData[__instance.ActionIndex] as ItemActionRanged.ItemActionDataRanged; + if (!_entity.MovementRunning && !_entity.AimingGun && !player.bLerpCameraFlag && _actionData != null && !_entity.inventory.holdingItem.IsActionRunning(_entity.inventory.holdingItemData) && !__instance.CanReload(_actionData) && (_entity.inventory.holdingItemItemValue.Meta > 0 || inspectable.Instance.allowEmptyInspect)) + { + _entity.emodel.avatarController._setTrigger("weaponInspect", true); + return false; + } + } + return true; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ExecuteAction))] + [HarmonyPostfix] + private static void Postfix_ExecuteAction_ItemActionRanged(ItemActionRanged __instance, ItemActionData _actionData) + { + if (_actionData is ItemActionRanged.ItemActionDataRanged rangedData) + { + int burstCount = __instance.GetBurstCount(_actionData); + _actionData.invData.holdingEntity.emodel.avatarController._setBool("TriggerPulled", rangedData.bPressed && rangedData.curBurstCount < burstCount, true); + } + } + + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.LateInitAll))] + [HarmonyPostfix] + private static void Postfix_LateInitAll_ItemClass() + { + AnimationRiggingManager.ParseItemIDs(); + } + + [HarmonyPatch(typeof(Animator), nameof(Animator.Rebind), new Type[0])] + [HarmonyReversePatch(HarmonyReversePatchType.Original)] + public static void RebindNoDefault(this Animator __instance) + { + IEnumerable Transpiler(IEnumerable instructions) + { + if (instructions == null) + { + yield break; + } + foreach (var ins in instructions) + { + if (ins.opcode == OpCodes.Ldc_I4_1) + { + yield return new CodeInstruction(OpCodes.Ldc_I4_0); + } + else + { + yield return ins; + } + } + } + _ = Transpiler(null); + } + + //[HarmonyPatch(typeof(ItemActionDynamic), nameof(ItemActionDynamic.GetExecuteActionGrazeTarget))] + //[HarmonyPostfix] + //private static void Postfix_Test2(WorldRayHitInfo[] __result) + //{ + // Log.Out($"World ray info count: {__result.Length}"); + //} + + //[HarmonyPatch(typeof(ItemActionDynamic), nameof(ItemActionDynamic.hitTarget))] + //[HarmonyPostfix] + //private static void Postfix_hittest(ItemActionData _actionData, WorldRayHitInfo hitInfo, bool _isGrazingHit = false) + //{ + // Log.Out($"HIT TARGET! IsGrazing: {_isGrazingHit}\n{StackTraceUtility.ExtractStackTrace()}"); + //} + + //[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController._setTrigger))] + //[HarmonyPostfix] + //private static void Postfix_AvatarLocalPlayerController_SetTrigger(int _pid, AvatarLocalPlayerController __instance) + //{ + // AnimationRiggingManager.SetTrigger(_pid, __instance.entity as EntityPlayer); + //} + + //[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController._resetTrigger))] + //[HarmonyPostfix] + //private static void Postfix_AvatarLocalPlayerController_ResetTrigger(int _pid, AvatarLocalPlayerController __instance) + //{ + // AnimationRiggingManager.ResetTrigger(_pid, __instance.entity as EntityPlayer); + //} + + //[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController._setFloat))] + //[HarmonyPostfix] + //private static void Postfix_AvatarLocalPlayerController_SetFloat(int _pid, float _value, AvatarLocalPlayerController __instance) + //{ + // AnimationRiggingManager.SetFloat(_pid, _value, __instance.entity as EntityPlayer); + //} + + //[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController._setBool))] + //[HarmonyPostfix] + //private static void Postfix_AvatarLocalPlayerController_SetBool(int _pid, bool _value, AvatarLocalPlayerController __instance) + //{ + // AnimationRiggingManager.SetBool(_pid, _value, __instance.entity as EntityPlayer); + //} + + //[HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController._setInt))] + //[HarmonyPostfix] + //private static void Postfix_AvatarLocalPlayerController_SetInt(int _pid, int _value, AvatarLocalPlayerController __instance) + //{ + // AnimationRiggingManager.SetInt(_pid, _value, __instance.entity as EntityPlayer); + //} + + //[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController._setTrigger))] + //[HarmonyPostfix] + //private static void Postfix_LegacyAvatarController_SetTrigger(int _propertyHash, LegacyAvatarController __instance) + //{ + // AnimationRiggingManager.SetTrigger(_propertyHash, __instance.entity as EntityPlayer); + //} + + //[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController._resetTrigger))] + //[HarmonyPostfix] + //private static void Postfix_LegacyAvatarController_ResetTrigger(int _propertyHash, LegacyAvatarController __instance) + //{ + // AnimationRiggingManager.ResetTrigger(_propertyHash, __instance.entity as EntityPlayer); + //} + + //[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController._setFloat))] + //[HarmonyPostfix] + //private static void Postfix_LegacyAvatarController_SetFloat(int _propertyHash, float _value, LegacyAvatarController __instance) + //{ + // AnimationRiggingManager.SetFloat(_propertyHash, _value, __instance.entity as EntityPlayer); + //} + + //[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController._setBool))] + //[HarmonyPostfix] + //private static void Postfix_LegacyAvatarController_SetBool(int _propertyHash, bool _value, LegacyAvatarController __instance) + //{ + // AnimationRiggingManager.SetBool(_propertyHash, _value, __instance.entity as EntityPlayer); + //} + + //[HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController._setInt))] + //[HarmonyPostfix] + //private static void Postfix_LegacyAvatarController_SetInt(int _propertyHash, int _value, LegacyAvatarController __instance) + //{ + // AnimationRiggingManager.SetInt(_propertyHash, _value, __instance.entity as EntityPlayer); + //} + + [HarmonyPatch(typeof(AvatarLocalPlayerController), nameof(AvatarLocalPlayerController._resetTrigger), typeof(int), typeof(bool))] + [HarmonyReversePatch(HarmonyReversePatchType.Original)] + public static void VanillaResetTrigger(AvatarLocalPlayerController __instance, int _pid, bool _netsync = true) + { + + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController.TryGetTrigger), new[] { typeof(int), typeof(bool) }, new[] { ArgumentType.Normal, ArgumentType.Out })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_TryGetTrigger_AvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool))); + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController.TryGetBool), new[] { typeof(int), typeof(bool) }, new[] { ArgumentType.Normal, ArgumentType.Out })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_TryGetBool_AvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool))); + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController.TryGetInt), new[] { typeof(int), typeof(int) }, new[] { ArgumentType.Normal, ArgumentType.Out })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_TryGetInt_AvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt))); + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController.TryGetFloat), new[] { typeof(int), typeof(float) }, new[] { ArgumentType.Normal, ArgumentType.Out })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_TryGetFloat_AvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedFloat))); + } + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.TryGetTrigger), new[] { typeof(int), typeof(bool) }, new[] { ArgumentType.Normal, ArgumentType.Out })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_TryGetTrigger_AvatarMultiBodyController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool))); + } + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.TryGetBool), new[] { typeof(int), typeof(bool) }, new[] { ArgumentType.Normal, ArgumentType.Out })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_TryGetBool_AvatarMultiBodyController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool))); + } + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.TryGetInt), new[] { typeof(int), typeof(int) }, new[] { ArgumentType.Normal, ArgumentType.Out })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_TryGetInt_AvatarMultiBodyController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt))); + } + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.TryGetFloat), new[] { typeof(int), typeof(float) }, new[] { ArgumentType.Normal, ArgumentType.Out })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_TryGetFloat_AvatarMultiBodyController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedFloat))); + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController._setBool), new[] { typeof(int), typeof(bool), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setBool_AvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetBool), new[] { typeof(int), typeof(bool) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedBool))); + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController._setTrigger), new[] { typeof(int), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setTrigger_AvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetTrigger), new[] { typeof(int)}), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedTrigger))); + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController._resetTrigger), new[] { typeof(int), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_resetTrigger_AvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.ResetTrigger), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.ResetWrappedTrigger))); + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController._setInt), new[] { typeof(int), typeof(int), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setInt_AvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetInteger), new[] { typeof(int), typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedInt))); + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController._setFloat), new[] { typeof(int), typeof(float), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setFloat_AvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedFloat))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetFloat), new[] { typeof(int), typeof(float) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedFloat))); + } + + [HarmonyPatch(typeof(AvatarCharacterController), nameof(AvatarCharacterController._setBool), new[] { typeof(int), typeof(bool), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setBool_AvatarCharacterController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetBool), new[] { typeof(int), typeof(bool) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedBool))); + } + + [HarmonyPatch(typeof(AvatarCharacterController), nameof(AvatarCharacterController._setTrigger), new[] { typeof(int), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setTrigger_AvatarCharacterController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetTrigger), new[] { typeof(int)}), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedTrigger))); + } + + [HarmonyPatch(typeof(AvatarCharacterController), nameof(AvatarCharacterController._resetTrigger), new[] { typeof(int), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_resetTrigger_AvatarCharacterController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.ResetTrigger), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.ResetWrappedTrigger))); + } + + [HarmonyPatch(typeof(AvatarCharacterController), nameof(AvatarCharacterController._setInt), new[] { typeof(int), typeof(int), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setInt_AvatarCharacterController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetInteger), new[] { typeof(int), typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedInt))); + } + + [HarmonyPatch(typeof(AvatarCharacterController), nameof(AvatarCharacterController._setFloat), new[] { typeof(int), typeof(float), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setFloat_AvatarCharacterController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetFloat), new[] { typeof(int), typeof(float) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedFloat))); + } + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController._setBool), new[] { typeof(int), typeof(bool), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setBool_AvatarMultiBodyController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetBool), new[] { typeof(int), typeof(bool) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedBool))); + } + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController._setTrigger), new[] { typeof(int), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setTrigger_AvatarMultiBodyController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetTrigger), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedTrigger))); + } + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController._resetTrigger), new[] { typeof(int), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_resetTrigger_AvatarMultiBodyController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.ResetTrigger), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.ResetWrappedTrigger))); + } + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController._setInt), new[] { typeof(int), typeof(int), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setInt_AvatarMultiBodyController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetInteger), new[] { typeof(int), typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedInt))); + } + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController._setFloat), new[] { typeof(int), typeof(float), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setFloat_AvatarMultiBodyController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedFloat))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetFloat), new[] { typeof(int), typeof(float) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedFloat))); + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController.GetParameterName))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_GetParameterName_AvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.PropertyGetter(typeof(Animator), nameof(Animator.parameters)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedParameters))); + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController.SyncAnimParameters))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SyncAnimParameters_AvatarController(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.MethodReplacer( + AccessTools.PropertyGetter(typeof(Animator), nameof(Animator.parameters)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedParameters))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedFloat))) + .ToList(); + + //var lbd_wrapper = generator.DeclareLocal(typeof(IAnimatorWrapper)); + + //var fld_anim = AccessTools.Field(typeof(AvatarController), nameof(AvatarController.anim)); + + //for (int i = 1; i < codes.Count; i++) + //{ + // if (codes[i].opcode == OpCodes.Stloc_0) + // { + // codes.InsertRange(i + 1, new[] + // { + // new CodeInstruction(OpCodes.Ldarg_0), + // CodeInstruction.LoadField(typeof(AvatarController), nameof(AvatarController.anim)), + // CodeInstruction.Call(typeof(KFExtensions), nameof(KFExtensions.GetAnimatorWrapper)), + // new CodeInstruction(OpCodes.Stloc_S, lbd_wrapper) + // }); + // i += 4; + // } + // else if (codes[i].opcode == OpCodes.Ldloc_3 && codes[i - 1].LoadsField(fld_anim)) + // { + // codes.Insert(i - 2, new CodeInstruction(OpCodes.Ldloc_S, lbd_wrapper).WithLabels(codes[i - 2].ExtractLabels())); + // codes.RemoveRange(i - 1, 2); + // i--; + // } + //} + + return codes; + } + + [HarmonyPatch(typeof(AvatarSDCSController), nameof(AvatarSDCSController.LateUpdate))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_LateUpdate_AvatarSDCSController(IEnumerable instructions, ILGenerator generator) + { + var mtd_getbool = AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(int) }); + var mtd_getint = AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }); + var mtd_getfloat = AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(int) }); + var mtd_istransition = AccessTools.Method(typeof(Animator),nameof(Animator.IsInTransition), new[] { typeof(int) }); + var mtd_updatespine = AccessTools.Method(typeof(LegacyAvatarController), nameof(LegacyAvatarController.updateSpineRotation)); + var fld_reload = AccessTools.Field(typeof(AvatarController), nameof(AvatarController.reloadHash)); + var mtd_getvanillabool = AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool)); + var mtd_getvanillaint = AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt)); + var mtd_getvanillafloat = AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedFloat)); + var mtd_isvanillatransition = AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.IsVanillaInTransition)); + var codes = instructions.Manipulator(ins => ins.opcode == OpCodes.Ldstr, ins => + { + switch (ins.operand) + { + case "Reload": + ins.opcode = OpCodes.Ldsfld; + ins.operand = fld_reload; + break; + } + }).MethodReplacer(AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(string) }), mtd_getbool) + .MethodReplacer(AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(string) }), mtd_getint) + .MethodReplacer(AccessTools.Method(typeof(Animator), nameof(Animator.GetFloat), new[] { typeof(string) }), mtd_getfloat) + .MethodReplacer(AccessTools.Method(typeof(Animator), nameof(Animator.SetBool), new[] { typeof(string), typeof(bool) }), AccessTools.Method(typeof(Animator), nameof(Animator.SetBool), new[] { typeof(int), typeof(bool) })) + .MethodReplacer(mtd_getbool, mtd_getvanillabool) + .MethodReplacer(mtd_getint, mtd_getvanillaint) + .MethodReplacer(mtd_getfloat, mtd_getvanillafloat) + .MethodReplacer(mtd_istransition, mtd_isvanillatransition) + .ToList(); + + //var lbd_wrapper = generator.DeclareLocal(typeof(IAnimatorWrapper)); + + //for (var i = 0; i < codes.Count; i++) + //{ + // if (codes[i].Calls(mtd_updatespine)) + // { + // codes.InsertRange(i + 1, new[] + // { + // new CodeInstruction(OpCodes.Ldarg_0), + // CodeInstruction.LoadField(typeof(AvatarController), nameof(AvatarController.anim)), + // CodeInstruction.Call(typeof(KFExtensions), nameof(KFExtensions.GetItemAnimatorWrapper)), + // new CodeInstruction(OpCodes.Stloc_S, lbd_wrapper) + // }); + // i += 4; + // } + // else if (codes[i].Calls(mtd_getvanillabool) || codes[i].Calls(mtd_getvanillafloat) || codes[i].Calls(mtd_getvanillaint) || codes[i].Calls(mtd_isvanillatransition)) + // { + // codes.Insert(i - 3, new CodeInstruction(OpCodes.Ldloc_S, lbd_wrapper).WithLabels(codes[i - 3].ExtractLabels())); + // codes.RemoveRange(i - 2, 2); + // i--; + // } + //} + //foreach (var code in codes) + //{ + // Log.Out(code.ToString()); + //} + return codes; + } + + [HarmonyPatch(typeof(AvatarSDCSController), nameof(AvatarSDCSController.updateLayerStateInfo))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_updateLayerStateInfo_AvatarSDCSController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetCurrentAnimatorStateInfo)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetCurrentVanillaStateInfo))); + } + + [HarmonyPatch(typeof(AvatarUMAController), nameof(AvatarUMAController.updateLayerStateInfo))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_updateLayerStateInfo_AvatarUMAController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetCurrentAnimatorStateInfo)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetCurrentVanillaStateInfo))); + } + + [HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController.updateLayerStateInfo))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_updateLayerStateInfo_LegacyAvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetCurrentAnimatorStateInfo)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetCurrentVanillaStateInfo))); + } + + [HarmonyPatch(typeof(AvatarSDCSController), nameof(AvatarSDCSController.setLayerWeights))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setLayerWeights_AvatarSDCSController(IEnumerable instructions) + { + int id = Animator.StringToHash("MinibikeIdle"); + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetLayerWeight)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetVanillaLayerWeight))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.IsInTransition)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.IsVanillaInTransition))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetBool), new[] { typeof(string) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedBool))) + .Manipulator(ins => ins.opcode == OpCodes.Ldstr, ins => { ins.opcode = OpCodes.Ldc_I4; ins.operand = id; }); + } + + [HarmonyPatch(typeof(LegacyAvatarController), nameof(LegacyAvatarController.setLayerWeights))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setLayerWeights_LegacyAvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetLayerWeight)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetVanillaLayerWeight))); + } + + [HarmonyPatch(typeof(AvatarUMAController), nameof(AvatarUMAController.setLayerWeights))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_setLayerWeights_AvatarUMAController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetLayerWeight)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetVanillaLayerWeight))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.IsInTransition)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.IsVanillaInTransition))); + } + + [HarmonyPatch(typeof(UMACharacterBodyAnimator), nameof(UMACharacterBodyAnimator.assignLayerWeights))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_assignLayerWeights_UMACharacterBodyAnimator(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetLayerWeight)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetVanillaLayerWeight))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.GetInteger), new[] { typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.GetWrappedInt))) + .MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.IsInTransition)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.IsVanillaInTransition))); + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController.Update))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_Update_AvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetLayerWeight)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetVanillaLayerWeight))); + } + + [HarmonyPatch(typeof(AvatarController), nameof(AvatarController.InitHitDuration))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_InitHitDuration_AvatarController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetLayerWeight)), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetVanillaLayerWeight))); + } + + private static int drunkHash = Animator.StringToHash("drunk"); + [HarmonyPatch(typeof(FirstPersonAnimator), nameof(FirstPersonAnimator.SetDrunk))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SetDrunk_FirstPersonAnimator(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetFloat), new[] { typeof(string), typeof(float) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedFloat))) + .Manipulator(ins => ins.LoadsConstant("drunk"), + ins => + { + ins.opcode = OpCodes.Ldsfld; + ins.operand = AccessTools.Field(typeof(AnimationRiggingPatches), nameof(AnimationRiggingPatches.drunkHash)); + }); + } + + [HarmonyPatch(typeof(AvatarMultiBodyController), nameof(AvatarMultiBodyController.SetVehicleAnimation))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SetVehicleAnimation_AvatarMultiBodyController(IEnumerable instructions) + { + return instructions.MethodReplacer( + AccessTools.Method(typeof(Animator), nameof(Animator.SetInteger), new[] { typeof(string), typeof(int) }), + AccessTools.Method(typeof(KFExtensions), nameof(KFExtensions.SetWrappedInt))); + } + //BodyAnimator.LateUpdate + //UMACharacterBodyAnimator.LateUpdate + //BodyAnimator.cacheLayerStateInfo + //UMACharacterBodyAnimator.cacheLayerStateInfo + //not used +} diff --git a/Harmony/BackgroundInventoryUpdatePatch.cs b/Harmony/BackgroundInventoryUpdatePatch.cs new file mode 100644 index 0000000..4e8eb4b --- /dev/null +++ b/Harmony/BackgroundInventoryUpdatePatch.cs @@ -0,0 +1,51 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.StaticManagers; + +namespace KFCommonUtilityLib.Harmony +{ + [HarmonyPatch] + public class BackgroundInventoryUpdatePatch + { + [HarmonyPatch(typeof(Inventory), nameof(Inventory.clearSlotByIndex))] + [HarmonyPostfix] + private static void Postfix_clearSlotByIndex_Inventory(Inventory __instance, int _idx) + { + BackgroundInventoryUpdateManager.UnregisterUpdater(__instance.entity, _idx); + } + + [HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.OnEntityDeath))] + [HarmonyPostfix] + private static void Postfix_OnEntityDeath_EntityAlive(EntityAlive __instance) + { + BackgroundInventoryUpdateManager.UnregisterUpdater(__instance); + } + + [HarmonyPatch(typeof(Inventory), nameof(Inventory.OnUpdate))] + [HarmonyPostfix] + private static void Postfix_OnUpdate_Inventory(Inventory __instance) + { + BackgroundInventoryUpdateManager.Update(__instance.entity); + } + + [HarmonyPatch(typeof(GameManager), nameof(GameManager.SaveAndCleanupWorld))] + [HarmonyPostfix] + private static void Postfix_SaveAndCleanupWorld_GameManager() + { + BackgroundInventoryUpdateManager.Cleanup(); + } + + [HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.AttachToEntity))] + [HarmonyPostfix] + private static void Postfix_AttachToEntity_EntityAlive(EntityAlive __instance) + { + BackgroundInventoryUpdateManager.DisableUpdater(__instance); + } + + [HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.Detach))] + [HarmonyPostfix] + private static void Postfix_Detach_EntityAlive(EntityAlive __instance) + { + BackgroundInventoryUpdateManager.EnableUpdater(__instance); + } + } +} diff --git a/Harmony/DamagePatches.cs b/Harmony/DamagePatches.cs new file mode 100644 index 0000000..12f71cc --- /dev/null +++ b/Harmony/DamagePatches.cs @@ -0,0 +1,174 @@ +using HarmonyLib; +using System.Collections.Generic; +using System.Reflection.Emit; +using UniLinq; +using UnityEngine; + +[HarmonyPatch] +public static class DamagePatches +{ + [HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.damageEntityLocal))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_damageEntityLocal_EntityAlive(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_calc = AccessTools.Method(typeof(Equipment), nameof(Equipment.CalcDamage)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_calc)) + { + codes[i] = CodeInstruction.Call(typeof(DamagePatches), nameof(DamagePatches.CalcEquipmentDamage)); + codes.RemoveRange(i - 12, 12); + codes.InsertRange(i - 12, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)), + CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.Other)) + }); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemActionAttack), nameof(ItemActionAttack.Hit))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_Hit_ItemActionAttack(IEnumerable instructions) + { + var codes = instructions.ToList(); + var mtd_getdamagegroup = AccessTools.Method(typeof(DamageSource), nameof(DamageSource.GetEntityDamageEquipmentSlotGroup)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_getdamagegroup)) + { + codes.InsertRange(i + 3, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, codes[i - 2].operand), + new CodeInstruction(OpCodes.Ldloc_S, codes[i - 1].operand), + CodeInstruction.Call(typeof(DamageSource), nameof(DamageSource.GetEntityDamageBodyPart)), + CodeInstruction.Call(typeof(DamagePatches), nameof(DamagePatches.GetBodyPartTags)), + CodeInstruction.Call(typeof(FastTags), "op_BitwiseOr") + }); + break; + } + } + return codes; + } + + private static void CalcEquipmentDamage(Equipment equipment, ref DamageResponse damageResponse, EntityAlive attacker) + { + damageResponse.ArmorDamage = damageResponse.Strength; + if (damageResponse.Source.DamageTypeTag.Test_AnySet(Equipment.physicalDamageTypes)) + { + if (damageResponse.Strength > 0) + { + float totalPhysicalArmorResistPercent = GetTotalPhysicalArmorResistPercent(equipment, in damageResponse, attacker) * .01f; + damageResponse.ArmorDamage = Utils.FastMax((totalPhysicalArmorResistPercent > 0f) ? 1 : 0, Mathf.RoundToInt((float)damageResponse.Strength * totalPhysicalArmorResistPercent)); + damageResponse.Strength -= damageResponse.ArmorDamage; + return; + } + } + else + { + damageResponse.Strength = Mathf.RoundToInt(Utils.FastMax(0f, (float)damageResponse.Strength * (1f - EffectManager.GetValue(PassiveEffects.ElementalDamageResist, null, 0f, equipment.m_entity, null, damageResponse.Source.DamageTypeTag) * .01f))); + damageResponse.ArmorDamage = Mathf.RoundToInt((float)Utils.FastMax(0, damageResponse.ArmorDamage - damageResponse.Strength)); + } + } + + private static float GetTotalPhysicalArmorResistPercent(Equipment equipment, in DamageResponse damageResponse, EntityAlive attacker) + { + if (!equipment?.m_entity) + return 0f; + FastTags bodyPartTags = GetBodyPartTags(damageResponse.HitBodyPart); + float resist = EffectManager.GetValue(PassiveEffects.PhysicalDamageResist, null, 0f, equipment.m_entity, null, Equipment.coreDamageResist | bodyPartTags); + if (attacker) + { + attacker.MinEventContext.Other = equipment.m_entity; + attacker.MinEventContext.ItemValue = damageResponse.Source.AttackingItem ?? ItemValue.None; + if (damageResponse.Source.AttackingItem != null) + { + if (damageResponse.Source.AttackingItem.ItemClass.Actions[1] is ItemActionProjectile) + { + return MultiActionReversePatches.ProjectileGetValue(PassiveEffects.TargetArmor, damageResponse.Source.AttackingItem, resist, attacker, null, damageResponse.Source.AttackingItem.ItemClass.ItemTags | bodyPartTags); + } + return EffectManager.GetValue(PassiveEffects.TargetArmor, damageResponse.Source.AttackingItem, resist, attacker, null, damageResponse.Source.AttackingItem.ItemClass.ItemTags | bodyPartTags); + } + return EffectManager.GetValue(PassiveEffects.TargetArmor, null, resist, attacker, null, bodyPartTags); + } + return resist; + } + + public static FastTags GetBodyPartTags(EnumBodyPartHit bodyparts) + { + if ((bodyparts & EnumBodyPartHit.LeftUpperArm) > EnumBodyPartHit.None) + { + return LeftUpperArmTags; + } + if ((bodyparts & EnumBodyPartHit.LeftLowerArm) > EnumBodyPartHit.None) + { + return LeftLowerArmTags; + } + if ((bodyparts & EnumBodyPartHit.RightUpperArm) > EnumBodyPartHit.None) + { + return RightUpperArmTags; + } + if ((bodyparts & EnumBodyPartHit.RightLowerArm) > EnumBodyPartHit.None) + { + return RightLowerArmTags; + } + if ((bodyparts & EnumBodyPartHit.LeftUpperLeg) > EnumBodyPartHit.None) + { + return LeftUpperLegTags; + } + if ((bodyparts & EnumBodyPartHit.LeftLowerLeg) > EnumBodyPartHit.None) + { + return LeftLowerLegTags; + } + if ((bodyparts & EnumBodyPartHit.RightUpperLeg) > EnumBodyPartHit.None) + { + return RightUpperLegTags; + } + if ((bodyparts & EnumBodyPartHit.RightLowerLeg) > EnumBodyPartHit.None) + { + return RightLowerLegTags; + } + if ((bodyparts & EnumBodyPartHit.Head) > EnumBodyPartHit.None) + { + return HeadTags; + } + if ((bodyparts & EnumBodyPartHit.Torso) > EnumBodyPartHit.None) + { + return TorsoTags; + } + if ((bodyparts & EnumBodyPartHit.Special) > EnumBodyPartHit.None) + { + return SpecialTags; + } + return FastTags.none; + } + + private static FastTags TorsoTags = FastTags.Parse("torso"); + private static FastTags HeadTags = FastTags.Parse("head"); + private static FastTags SpecialTags = FastTags.Parse("special"); + private static FastTags ArmsTags = FastTags.Parse("arms"); + private static FastTags UpperArmsTags = FastTags.Parse("upperArms"); + private static FastTags LowerArmsTags = FastTags.Parse("lowerArms"); + private static FastTags LeftArmTags = FastTags.Parse("leftArms"); + private static FastTags RightArmTags = FastTags.Parse("rightArms"); + private static FastTags LeftUpperArmTags = FastTags.Parse("leftUpperArms") | LeftArmTags | UpperArmsTags | ArmsTags; + private static FastTags LeftLowerArmTags = FastTags.Parse("leftLowerArms") | LeftArmTags | LowerArmsTags | ArmsTags; + private static FastTags RightUpperArmTags = FastTags.Parse("rightUpperArms") | RightArmTags | UpperArmsTags | ArmsTags; + private static FastTags RightLowerArmTags = FastTags.Parse("rightLowerArms") | RightArmTags | LowerArmsTags | ArmsTags; + private static FastTags LegsTags = FastTags.Parse("legs"); + private static FastTags UpperLegsTags = FastTags.Parse("upperLegs"); + private static FastTags LowerLegsTags = FastTags.Parse("lowerLegs"); + private static FastTags LeftLegTags = FastTags.Parse("leftLegs"); + private static FastTags RightLegTags = FastTags.Parse("rightLegs"); + private static FastTags LeftUpperLegTags = FastTags.Parse("leftUpperLegs") | LeftLegTags | UpperLegsTags | LegsTags; + private static FastTags LeftLowerLegTags = FastTags.Parse("leftLowerLegs") | LeftLegTags | LowerLegsTags | LegsTags; + private static FastTags RightUpperLegTags = FastTags.Parse("rightUpperLegs") | RightLegTags | UpperLegsTags | LegsTags; + private static FastTags RightLowerLegTags = FastTags.Parse("rightLowerLegs") | RightLegTags | LowerLegsTags | LegsTags; +} \ No newline at end of file diff --git a/Harmony/DisplayMetaAsBuffPatch.cs b/Harmony/DisplayMetaAsBuffPatch.cs new file mode 100644 index 0000000..13638ec --- /dev/null +++ b/Harmony/DisplayMetaAsBuffPatch.cs @@ -0,0 +1,21 @@ +using HarmonyLib; + +namespace KFCommonUtilityLib.Harmony +{ + [HarmonyPatch] + public static class DisplayMetaAsBuffPatch + { + [HarmonyPatch(typeof(XUiM_PlayerBuffs), nameof(XUiM_PlayerBuffs.GetBuffDisplayInfo))] + [HarmonyPrefix] + private static bool Prefix_GetBuffDisplayInfo_XUiM_PlayerBuffs(EntityUINotification notification, ref string __result) + { + if (notification is DisplayAsBuffEntityUINotification && notification.Buff != null) + { + __result = notification.CurrentValue.ToString(); + return false; + } + + return true; + } + } +} diff --git a/Harmony/FPVLegPatches.cs b/Harmony/FPVLegPatches.cs new file mode 100644 index 0000000..d3d65a9 --- /dev/null +++ b/Harmony/FPVLegPatches.cs @@ -0,0 +1,34 @@ +using HarmonyLib; +using System.Collections.Generic; +using UniLinq; +using System.Reflection.Emit; + +namespace KFCommonUtilityLib.Harmony +{ + //[HarmonyPatch] + public static class FPVLegPatches + { + [HarmonyPatch(typeof(SDCSUtils), nameof(SDCSUtils.CreateVizTP))] + [HarmonyPrefix] + private static void Prefix_SDCSUtils_CreateTP(EntityAlive entity, ref bool isFPV, out bool __state) + { + __state = isFPV; + if (entity is EntityPlayerLocal) + { + entity.emodel.IsFPV = false; + isFPV = false; + } + } + + [HarmonyPatch(typeof(SDCSUtils), nameof(SDCSUtils.CreateVizTP))] + [HarmonyPostfix] + private static void Postfix_SDCSUtils_CreateTP(EntityAlive entity, ref bool isFPV, bool __state) + { + if (entity is EntityPlayerLocal) + { + entity.emodel.IsFPV = __state; + isFPV = __state; + } + } + } +} diff --git a/Harmony/HideMarkerOnAimPatch.cs b/Harmony/HideMarkerOnAimPatch.cs new file mode 100644 index 0000000..3408306 --- /dev/null +++ b/Harmony/HideMarkerOnAimPatch.cs @@ -0,0 +1,45 @@ +using HarmonyLib; +using UnityEngine; + +[HarmonyPatch] +public class HideMarkerOnAimPatch +{ + [HarmonyPatch(typeof(XUiC_OnScreenIcons), nameof(XUiC_OnScreenIcons.Init))] + [HarmonyPostfix] + private static void Postfix_Init_XUiC_OnScreenIcons(XUiC_OnScreenIcons __instance) + { + GameObject iconParent = new GameObject("AllIconParent"); + iconParent.transform.SetParent(__instance.ViewComponent.UiTransform); + iconParent.transform.localScale = Vector3.one; + } + + [HarmonyPatch(typeof(XUiC_OnScreenIcons), nameof(XUiC_OnScreenIcons.CreateIcon))] + [HarmonyPostfix] + private static void Postfix_CreateIcon_XUiC_OnScreenIcons(XUiC_OnScreenIcons __instance) + { + if (__instance.ViewComponent?.UiTransform) + { + __instance.screenIconList[__instance.screenIconList.Count - 1].Transform.SetParent(__instance.ViewComponent.UiTransform.Find("AllIconParent")); + } + } + + [HarmonyPatch(typeof(XUiC_OnScreenIcons), nameof(XUiC_OnScreenIcons.Update))] + [HarmonyPrefix] + private static bool Prefix_Update_XUiC_OnScreenIcons(XUiC_OnScreenIcons __instance) + { + GameObject iconParent = __instance.ViewComponent.UiTransform.Find("AllIconParent").gameObject; + if (!iconParent) + { + return true; + } + if (__instance.xui.playerUI.entityPlayer.bAimingGun) + { + iconParent.SetActive(false); + } + else + { + iconParent.SetActive(true); + } + return true; + } +} diff --git a/Harmony/Init.cs b/Harmony/Init.cs new file mode 100644 index 0000000..5eaa75b --- /dev/null +++ b/Harmony/Init.cs @@ -0,0 +1,96 @@ +using GearsAPI.Settings; +using GearsAPI.Settings.Global; +using GearsAPI.Settings.World; +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; +using System.Reflection; +using System.Runtime.InteropServices; + +public class CommonUtilityLibInit : IModApi +{ + private static bool inited = false; + internal static Harmony HarmonyInstance { get; private set; } + public void InitMod(Mod _modInstance) + { + if (inited) + return; + inited = true; + Log.Out(" Loading Patch: " + GetType()); + unsafe + { + Log.Out($"size of MultiActionIndice: {sizeof(MultiActionIndice)} marshal size: {Marshal.SizeOf()}"); + Log.Out($"{AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.StartHolding)).FullDescription()}"); + } + //QualitySettings.streamingMipmapsMemoryBudget = 4096; + DelayLoadModuleManager.RegisterDelayloadDll("FullautoLauncher", "FullautoLauncherAnimationRiggingCompatibilityPatch"); + //DelayLoadModuleManager.RegisterDelayloadDll("SMXcore", "SMXMultiActionCompatibilityPatch"); + //DelayLoadModuleManager.RegisterDelayloadDll("SCore", "SCoreEntityHitCompatibilityPatch"); + CustomEffectEnumManager.RegisterEnumType(); + CustomEffectEnumManager.RegisterEnumType(); + + ModuleManagers.ClearOutputFolder(); + ItemClassModuleManager.Init(); + ItemActionModuleManager.Init(); + + ModEvents.GameAwake.RegisterHandler(CommonUtilityPatch.InitShotStates); + ModEvents.GameAwake.RegisterHandler(CustomEffectEnumManager.InitDefault); + ModEvents.GameAwake.RegisterHandler(DelayLoadModuleManager.DelayLoad); + //ModEvents.GameAwake.RegisterHandler(AssemblyLocator.Init); + ModEvents.GameAwake.RegisterHandler(MultiActionUtils.SetMinEventArrays); + ModEvents.GameStartDone.RegisterHandler(RegisterKFEnums); + //DOES NOT WORK ON MULTIPLAYER? Patch to ItemClass.LateInitAll + //ModEvents.GameStartDone.RegisterHandler(AnimationRiggingManager.ParseItemIDs); + ModEvents.GameStartDone.RegisterHandler(MultiActionManager.PostloadCleanup); + //ModEvents.GameStartDone.RegisterHandler(CustomEffectEnumManager.PrintResults); + //ModEvents.GameUpdate.RegisterHandler(CommonUtilityPatch.ForceUpdateGC); + HarmonyInstance = new Harmony(GetType().ToString()); + HarmonyInstance.PatchAll(Assembly.GetExecutingAssembly()); + } + + private static void RegisterKFEnums() + { + CustomEnums.onSelfMagzineDeplete = CustomEffectEnumManager.RegisterOrGetEnum("onSelfMagzineDeplete"); + CustomEnums.onReloadAboutToStart = CustomEffectEnumManager.RegisterOrGetEnum("onReloadAboutToStart"); + CustomEnums.onRechargeValueUpdate = CustomEffectEnumManager.RegisterOrGetEnum("onRechargeValueUpdate"); + CustomEnums.onSelfItemSwitchMode = CustomEffectEnumManager.RegisterOrGetEnum("onSelfItemSwitchMode"); + CustomEnums.onSelfBurstModeChanged = CustomEffectEnumManager.RegisterOrGetEnum("onSelfBurstModeChanged"); + CustomEnums.onSelfFirstCVarSync = CustomEffectEnumManager.RegisterOrGetEnum("onSelfFirstCVarSync"); + CustomEnums.onSelfHoldingItemAssemble = CustomEffectEnumManager.RegisterOrGetEnum("onSelfHoldingItemAssemble"); + + CustomEnums.ReloadSpeedRatioFPV2TPV = CustomEffectEnumManager.RegisterOrGetEnum("ReloadSpeedRatioFPV2TPV"); + CustomEnums.RecoilSnappiness = CustomEffectEnumManager.RegisterOrGetEnum("RecoilSnappiness"); + CustomEnums.RecoilReturnSpeed = CustomEffectEnumManager.RegisterOrGetEnum("RecoilReturnSpeed"); + //CustomEnums.ProjectileImpactDamagePercentBlock = CustomEffectEnumManager.RegisterOrGetEnum("ProjectileImpactDamagePercentBlock"); + //CustomEnums.ProjectileImpactDamagePercentEntity = CustomEffectEnumManager.RegisterOrGetEnum("ProjectileImpactDamagePercentEntity"); + CustomEnums.PartialReloadCount = CustomEffectEnumManager.RegisterOrGetEnum("PartialReloadCount"); + + CustomEnums.CustomTaggedEffect = CustomEffectEnumManager.RegisterOrGetEnum("CustomTaggedEffect"); + CustomEnums.KickDegreeHorizontalModifier = CustomEffectEnumManager.RegisterOrGetEnum("KickDegreeHorizontalModifier"); + CustomEnums.KickDegreeVerticalModifier = CustomEffectEnumManager.RegisterOrGetEnum("KickDegreeVerticalModifier"); + CustomEnums.WeaponErgonomics = CustomEffectEnumManager.RegisterOrGetEnum("WeaponErgonomics"); + CustomEnums.RecoilCameraShakeStrength = CustomEffectEnumManager.RegisterOrGetEnum("RecoilCameraShakeStrength"); + CustomEnums.BurstShotInterval = CustomEffectEnumManager.RegisterOrGetEnum("BurstShotInterval"); + CustomEnums.MaxWeaponSpread = CustomEffectEnumManager.RegisterOrGetEnum("MaxWeaponSpread"); + } +} + +public class GearsImpl : IGearsModApi +{ + public void InitMod(IGearsMod modInstance) + { + + } + + public void OnGlobalSettingsLoaded(IModGlobalSettings modSettings) + { + RecoilManager.InitRecoilSettings(modSettings); + } + + public void OnWorldSettingsLoaded(IModWorldSettings worldSettings) + { + + } +} + diff --git a/Harmony/InvariableRPMPatches.cs b/Harmony/InvariableRPMPatches.cs new file mode 100644 index 0000000..8cc131c --- /dev/null +++ b/Harmony/InvariableRPMPatches.cs @@ -0,0 +1,73 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; + +namespace KFCommonUtilityLib.Harmony +{ + [HarmonyPatch] + public static class InvariableRPMPatches + { + //added as a transpiler so that it's applied before all post processing + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.OnHoldingUpdate))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_OnHoldingUpdate_ItemActionRanged(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_getvalue)) + { + int start = -1; + for (int j = i; j >= 0; j--) + { + if (codes[j].opcode == OpCodes.Stloc_0) + { + start = j + 2; + break; + } + } + if (start >= 0) + { + codes.InsertRange(i + 2, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.Call(typeof(InvariableRPMPatches), nameof(InvariableRPMPatches.CalcFixedRPM)) + }); + codes.RemoveRange(start, i - start + 2); + Log.Out("Invariable RPM Patch applied!"); + } + break; + } + } + + return codes; + } + + private static float CalcFixedRPM(ItemActionRanged rangedAction, ItemActionRanged.ItemActionDataRanged rangedData) + { + float res; + if (rangedAction is IModuleContainerFor actionModule) + { + float rpm = 60f / rangedData.OriginalDelay; + float perc = 1f; + var tags = rangedData.invData.item.ItemTags; + MultiActionManager.ModifyItemTags(rangedData.invData.itemValue, rangedData, ref tags); + rangedData.invData.item.Effects.ModifyValue(rangedData.invData.holdingEntity, PassiveEffects.RoundsPerMinute, ref rpm, ref perc, rangedData.invData.itemValue.Quality, tags); + res = rpm * perc; + //Log.Out($"fixed RPM {res}"); + } + else + { + res = EffectManager.GetValue(PassiveEffects.RoundsPerMinute, rangedData.invData.itemValue, 60f / rangedData.OriginalDelay, rangedData.invData.holdingEntity); + } + res = 60f / res; + return res; + } + } +} diff --git a/Harmony/ItemActionModulePatch.cs b/Harmony/ItemActionModulePatch.cs new file mode 100644 index 0000000..f25f2f0 --- /dev/null +++ b/Harmony/ItemActionModulePatch.cs @@ -0,0 +1,41 @@ +using HarmonyLib; +using HarmonyLib.Public.Patching; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System.Reflection; + +namespace KFCommonUtilityLib.Harmony +{ + [HarmonyPatch] + public static class ItemActionModulePatch + { + [HarmonyPatch(typeof(GameManager), nameof(GameManager.StartGame))] + [HarmonyPrefix] + private static bool Prefix_StartGame_GameManager() + { + ItemActionModuleManager.InitNew(); + return true; + } + + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.Init))] + [HarmonyPostfix] + private static void Postfix_Init_ItemClass(ItemClass __instance) + { + ItemActionModuleManager.CheckItem(__instance); + } + + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.LateInitAll))] + [HarmonyPrefix] + private static bool Prefix_LateInitAll_ItemClass() + { + ItemActionModuleManager.FinishAndLoad(); + return true; + } + + [HarmonyPatch(typeof(PatchManager), "GetRealMethod")] + [HarmonyReversePatch] + public static MethodBase GetRealMethod(MethodInfo method, bool useReplacement) + { + return null; + } + } +} diff --git a/Harmony/ModularPatches.cs b/Harmony/ModularPatches.cs new file mode 100644 index 0000000..7e9931f --- /dev/null +++ b/Harmony/ModularPatches.cs @@ -0,0 +1,343 @@ +using HarmonyLib; +using HarmonyLib.Public.Patching; +using System.Collections.Generic; +using UniLinq; +using System.Reflection; +using System.Reflection.Emit; +using System.Runtime.CompilerServices; +using System; + +namespace KFCommonUtilityLib.Harmony +{ + [HarmonyPatch] + public static class ModularPatches + { + [HarmonyPatch(typeof(GameManager), nameof(GameManager.StartGame))] + [HarmonyPrefix] + private static bool Prefix_StartGame_GameManager() + { + ModuleManagers.InitNew(); + return true; + } + + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.Init))] + [HarmonyPostfix] + private static void Postfix_Init_ItemClass(ItemClass __instance) + { + ItemClassModuleManager.CheckItem(__instance); + ItemActionModuleManager.CheckItem(__instance); + } + + [HarmonyPatch(typeof(GameManager), nameof(GameManager.worldInfoCo), MethodType.Enumerator)] + [HarmonyTranspiler] + private static IEnumerable Transpiler_worldInfoCo_GameManager(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_all = AccessTools.Method(typeof(WorldStaticData), nameof(WorldStaticData.AllConfigsReceivedAndLoaded)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_all)) + { + codes.Insert(i + 2, CodeInstruction.Call(typeof(ModuleManagers), nameof(ModuleManagers.FinishAndLoad)).WithLabels(codes[i + 2].ExtractLabels())); + break; + } + } + return codes; + } + + [HarmonyPatch(typeof(ConnectionManager), nameof(ConnectionManager.ServerReady))] + [HarmonyPrefix] + private static void Prefix_ServerReady_ConnectionManager() + { + ModuleManagers.FinishAndLoad(); + } + + [HarmonyPatch(typeof(WorldStaticData), nameof(WorldStaticData.ReloadAllXmlsSync))] + [HarmonyPrefix] + private static void Prefix_ReloadAllXmlsSync_WorldStaticData() + { + ModuleManagers.InitNew(); + } + + [HarmonyPatch(typeof(WorldStaticData), nameof(WorldStaticData.ReloadAllXmlsSync))] + [HarmonyPostfix] + private static void Postfix_ReloadAllXmlsSync_WorldStaticData() + { + ModuleManagers.FinishAndLoad(); + } + + [HarmonyPatch(typeof(GameManager), nameof(GameManager.Disconnect))] + [HarmonyPostfix] + private static void Postfix_Disconnect_GameManager() + { + ModuleManagers.Cleanup(); + } + + [HarmonyPatch(typeof(PatchManager), "GetRealMethod")] + [HarmonyReversePatch] + public static MethodBase GetRealMethod(MethodInfo method, bool useReplacement) + { + IEnumerable Transpiler(IEnumerable instructions) + { + if (instructions == null) + { + return null; + } + return new CodeInstruction[] + { + CodeInstruction.LoadField(typeof(PatchManager), "ReplacementToOriginals"), + CodeInstruction.LoadField(typeof(PatchManager), "ReplacementToOriginalsMono"), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.Call(typeof(ModularPatches), nameof(ModularPatches.GetPatched)), + new CodeInstruction(OpCodes.Ret) + }; + } + _ = Transpiler(null); + return null; + } + + private static MethodBase GetPatched(ConditionalWeakTable ReplacementToOriginals, Dictionary ReplacementToOriginalsMono, MethodInfo method) + { + MethodInfo methodInfo = method.Identifiable(); + ConditionalWeakTable replacementToOriginals = ReplacementToOriginals; + lock (replacementToOriginals) + { + foreach (var pair in replacementToOriginals) + { + if (pair.Value == method) + { + Log.Out($"Found method replacement {pair.Key.FullDescription()} for method {method.FullDescription()}"); + return pair.Key; + } + } + } + if (AccessTools.IsMonoRuntime) + { + long num = (long)method.MethodHandle.GetFunctionPointer(); + Dictionary replacementToOriginalsMono = ReplacementToOriginalsMono; + lock (replacementToOriginalsMono) + { + foreach (var pair in replacementToOriginalsMono) + { + if (pair.Value[0] == method) + { + Log.Out($"Found MONO method replacement {pair.Value[1].FullDescription()} for method {method.FullDescription()}"); + return pair.Value[1]; + } + } + } + } + return method; + } + + [HarmonyPatch(typeof(PatchManager), nameof(PatchManager.ToPatchInfo))] + [HarmonyReversePatch] + public static PatchInfo ToPatchInfoDontAdd(this MethodBase methodBase) + { + IEnumerable Transpiler(IEnumerable instructions) + { + if (instructions == null) + { + return null; + } + + var codes = instructions.ToList(); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Dup) + { + codes[i - 1].WithLabels(codes[i - 3].ExtractLabels()); + codes.RemoveAt(i + 2); + codes.RemoveAt(i); + codes.RemoveRange(i - 3, 2); + break; + } + } + return codes; + } + _ = Transpiler(null); + return null; + } + + [HarmonyPatch(typeof(PatchInfo), "AddTranspilers")] + [HarmonyReversePatch] + public static void AddTranspilers(this PatchInfo self, string owner, params HarmonyMethod[] methods) + { + } + + public static PatchInfo Copy(this PatchInfo self) + { + var res = new PatchInfo(); + res.prefixes = new Patch[self.prefixes.Length]; + res.postfixes = new Patch[self.postfixes.Length]; + res.transpilers = new Patch[self.transpilers.Length]; + res.finalizers = new Patch[self.finalizers.Length]; + res.ilmanipulators = new Patch[self.ilmanipulators.Length]; + Array.Copy(self.prefixes, res.prefixes, res.prefixes.Length); + Array.Copy(self.postfixes, res.postfixes, res.postfixes.Length); + Array.Copy(self.transpilers, res.transpilers, res.transpilers.Length); + Array.Copy(self.finalizers, res.finalizers, res.finalizers.Length); + Array.Copy(self.ilmanipulators, res.ilmanipulators, res.ilmanipulators.Length); + return res; + } + + //public static MethodBase GetOriginalMethod(this HarmonyMethod attr) + //{ + // try + // { + // MethodType? methodType = attr.methodType; + // if (methodType != null) + // { + // switch (methodType.GetValueOrDefault()) + // { + // case MethodType.Normal: + // if (attr.methodName == null) + // { + // return null; + // } + // return AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes, null); + // case MethodType.Getter: + // { + // if (attr.methodName == null) + // { + // PropertyInfo propertyInfo = AccessTools.DeclaredIndexer(attr.declaringType, attr.argumentTypes); + // return (propertyInfo != null) ? propertyInfo.GetGetMethod(true) : null; + // } + // PropertyInfo propertyInfo2 = AccessTools.DeclaredProperty(attr.declaringType, attr.methodName); + // return (propertyInfo2 != null) ? propertyInfo2.GetGetMethod(true) : null; + // } + // case MethodType.Setter: + // { + // if (attr.methodName == null) + // { + // PropertyInfo propertyInfo3 = AccessTools.DeclaredIndexer(attr.declaringType, attr.argumentTypes); + // return (propertyInfo3 != null) ? propertyInfo3.GetSetMethod(true) : null; + // } + // PropertyInfo propertyInfo4 = AccessTools.DeclaredProperty(attr.declaringType, attr.methodName); + // return (propertyInfo4 != null) ? propertyInfo4.GetSetMethod(true) : null; + // } + // case MethodType.Constructor: + // return AccessTools.DeclaredConstructor(attr.declaringType, attr.argumentTypes, false); + // case MethodType.StaticConstructor: + // return AccessTools.GetDeclaredConstructors(attr.declaringType, null).FirstOrDefault((ConstructorInfo c) => c.IsStatic); + // case MethodType.Enumerator: + // if (attr.methodName == null) + // { + // return null; + // } + // return AccessTools.EnumeratorMoveNext(AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes, null)); + // case MethodType.Async: + // if (attr.methodName == null) + // { + // return null; + // } + // return AccessTools.AsyncMoveNext(AccessTools.DeclaredMethod(attr.declaringType, attr.methodName, attr.argumentTypes, null)); + // } + // } + // } + // catch (AmbiguousMatchException ex) + // { + // throw new Exception("Ambiguous match for HarmonyMethod[" + attr.ToString() + "]", ex.InnerException ?? ex); + // } + // return null; + //} + + //public static MethodBase GetBaseMethod(this HarmonyMethod attr) + //{ + // try + // { + // MethodType? methodType = attr.methodType; + // if (methodType != null) + // { + // switch (methodType.GetValueOrDefault()) + // { + // case MethodType.Normal: + // if (attr.methodName == null) + // { + // return null; + // } + // return AccessTools.Method(attr.declaringType, attr.methodName, attr.argumentTypes, null); + // case MethodType.Getter: + // { + // if (attr.methodName == null) + // { + // PropertyInfo propertyInfo = AccessTools.Indexer(attr.declaringType, attr.argumentTypes); + // return (propertyInfo != null) ? propertyInfo.GetGetMethod(true) : null; + // } + // PropertyInfo propertyInfo2 = AccessTools.Property(attr.declaringType, attr.methodName); + // return (propertyInfo2 != null) ? propertyInfo2.GetGetMethod(true) : null; + // } + // case MethodType.Setter: + // { + // if (attr.methodName == null) + // { + // PropertyInfo propertyInfo3 = AccessTools.Indexer(attr.declaringType, attr.argumentTypes); + // return (propertyInfo3 != null) ? propertyInfo3.GetSetMethod(true) : null; + // } + // PropertyInfo propertyInfo4 = AccessTools.Property(attr.declaringType, attr.methodName); + // return (propertyInfo4 != null) ? propertyInfo4.GetSetMethod(true) : null; + // } + // case MethodType.Constructor: + // return AccessTools.Constructor(attr.declaringType, attr.argumentTypes, false); + // case MethodType.StaticConstructor: + // return AccessTools.GetDeclaredConstructors(attr.declaringType, null).FirstOrDefault((ConstructorInfo c) => c.IsStatic); + // case MethodType.Enumerator: + // if (attr.methodName == null) + // { + // return null; + // } + // return AccessTools.EnumeratorMoveNext(AccessTools.Method(attr.declaringType, attr.methodName, attr.argumentTypes, null)); + // case MethodType.Async: + // if (attr.methodName == null) + // { + // return null; + // } + // return AccessTools.AsyncMoveNext(AccessTools.Method(attr.declaringType, attr.methodName, attr.argumentTypes, null)); + // } + // } + // } + // catch (AmbiguousMatchException ex) + // { + // throw new Exception("Ambiguous match for HarmonyMethod[" + attr.ToString() + "]", ex.InnerException ?? ex); + // } + // return null; + //} + } + + [HarmonyPatch] + public static class PatchToolsPatches + { + public static MethodBase TargetMethod() + { + return AccessTools.DeclaredMethod(AccessTools.TypeByName("HarmonyLib.PatchTools"), "GetOriginalMethod"); + } + + [HarmonyReversePatch] + public static MethodBase GetOriginalMethod(this HarmonyMethod attr) + { + return null; + } + + [HarmonyReversePatch] + public static MethodBase GetBaseMethod(this HarmonyMethod attr) + { + IEnumerable Transpiler(IEnumerable instructions) + { + if (instructions == null) + return null; + return instructions.MethodReplacer(AccessTools.Method(typeof(AccessTools), nameof(AccessTools.DeclaredMethod), new[] { typeof(Type), typeof(string), typeof(Type[]), typeof(Type[]) }), + AccessTools.Method(typeof(AccessTools), nameof(AccessTools.Method), new[] { typeof(Type), typeof(string), typeof(Type[]), typeof(Type[]) })) + .MethodReplacer(AccessTools.Method(typeof(AccessTools), nameof(AccessTools.DeclaredIndexer)), + AccessTools.Method(typeof(AccessTools), nameof(AccessTools.Indexer))) + .MethodReplacer(AccessTools.Method(typeof(AccessTools), nameof(AccessTools.DeclaredProperty), new[] { typeof(Type), typeof(string) }), + AccessTools.Method(typeof(AccessTools), nameof(AccessTools.Property), new[] { typeof(Type), typeof(string) })) + .MethodReplacer(AccessTools.Method(typeof(AccessTools), nameof(AccessTools.DeclaredConstructor)), + AccessTools.Method(typeof(AccessTools), nameof(AccessTools.Constructor))); + } + _ = Transpiler(null); + return null; + } + } +} diff --git a/Harmony/MultiActionPatches.cs b/Harmony/MultiActionPatches.cs new file mode 100644 index 0000000..e34b85b --- /dev/null +++ b/Harmony/MultiActionPatches.cs @@ -0,0 +1,2909 @@ +using GameEvent.SequenceActions; +using HarmonyLib; +using KFCommonUtilityLib.Scripts.NetPackages; +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Reflection.Emit; +using UniLinq; +using UnityEngine; + +namespace KFCommonUtilityLib.Harmony +{ + //done?: patch all accesses to ItemClass.Actions so that they process all actions + //done?: patch ItemClass.ExecuteAction, MinEvent triggers + //done: replace GameManager.ItemReload* + //done: patch ItemActionRanged.ConsumeAmmo + //todo: patch passive effect handling and trigger effect firing, in ItemValue.ModifyValue set action index from tags + //todo: patch trigger action index enum/ or just let it use secondary and tag check? + //todo: handle ItemActionAttack.GetDamageEntity/GetDamageBlock and call sites actionIndex + //todo: sell, assemble, scrap remove ammo + + //nope, not gonna work + //try old style action toggle, + //replace meta and ammo index when toggling, => solves ammo issue + //provide requirement for checking current mode, => solves effect group condition issue + //replace hardcoded action index with current mode => bulk patch is enough? + //ItemClass subclass? maybe not + //is inventory update on remote client really needed? put off + + //todo: figure out when is meta and ammo index used, how to set their value in minimum patches + //ExecuteAction, Reload, what's more? + //safe to work within ItemAction scope + //even if meta and ammo index is set accordingly, better keep checking them in reload script + [HarmonyPatch] + public static class MultiActionPatches + { + #region Run Correct ItemAction + + #region Ranged Reload + //Replace reload action index with animator item action index parameter + //set MinEventParams.ItemActionData before getting passive value + [HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateEnter))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_OnStateEnter_AnimatorRangedReloadState(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + LocalBuilder lbd_index = generator.DeclareLocal(typeof(int)); + + FieldInfo fld_action = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions)); + FieldInfo fld_actionData = AccessTools.Field(typeof(ItemInventoryData), nameof(ItemInventoryData.actionData)); + FieldInfo fld_meta = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.Meta)); + FieldInfo fld_ammoindex = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.SelectedAmmoTypeIndex)); + MethodInfo mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue)); + bool firstRet = true; + + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if ((code.LoadsField(fld_action) || code.LoadsField(fld_actionData)) && codes[i + 1].opcode == OpCodes.Ldc_I4_0) + { + //get correct ItemAction and data + codes[i + 1].opcode = OpCodes.Ldloc_S; + codes[i + 1].operand = lbd_index; + } + else if (code.Calls(mtd_getvalue)) + { + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(AnimatorRangedReloadState), "actionData"), + CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)), + CodeInstruction.LoadField(typeof(ItemInventoryData), nameof(ItemInventoryData.holdingEntity)), + CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(AnimatorRangedReloadState), "actionData"), + CodeInstruction.StoreField(typeof(MinEventParams), nameof(MinEventParams.ItemActionData)) + }); + break; + } + else if (code.opcode == OpCodes.Ret && firstRet) + { + firstRet = false; + var insert = new[] + { + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.GetActionIndexForEntity)), + new CodeInstruction(OpCodes.Stloc_S, lbd_index) + }; + insert[0].MoveLabelsFrom(codes[i + 1]); + codes.InsertRange(i + 1, insert); + } + } + + return codes; + } + + [HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateExit))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_OnStateExit_AnimatorRangedReloadState(IEnumerable instructions) + { + var codes = instructions.ToList(); + + MethodInfo mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue)); + + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.Calls(mtd_getvalue)) + { + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.actionData)), + CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)), + CodeInstruction.LoadField(typeof(ItemInventoryData), nameof(ItemInventoryData.holdingEntity)), + CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.actionData)), + CodeInstruction.StoreField(typeof(MinEventParams), nameof(MinEventParams.ItemActionData)) + }); + break; + } + } + + return codes; + } + #endregion + + //KEEP + #region Aiming + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.IsAimingGunPossible))] + [HarmonyPrefix] + private static bool Prefix_IsAimingGunPossible_EntityPlayerLocal(ref bool __result, EntityPlayerLocal __instance) + { + __result = true; + for (int i = 0; i < __instance.inventory.holdingItem.Actions.Length; i++) + { + ItemAction action = __instance.inventory.holdingItem.Actions[i]; + ItemActionData actionData = __instance.inventory.holdingItemData.actionData[i]; + __result &= (action == null || action.IsAimingGunPossible(actionData)); + } + return false; + } + #endregion + + //KEEP + #region Cancel bow draw + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.TryCancelBowDraw))] + [HarmonyPrefix] + private static bool Prefix_TryCancelBowDraw(EntityPlayerLocal __instance) + { + for (int i = 0; i < __instance.inventory.holdingItem.Actions.Length; i++) + { + ItemAction action = __instance.inventory.holdingItem.Actions[i]; + ItemActionData actionData = __instance.inventory.holdingItemData.actionData[i]; + if (action is ItemActionCatapult catapult) + { + action.CancelAction(actionData); + actionData.HasExecuted = false; + } + } + return false; + } + #endregion + + //KEEP + #region Consume wheel scroll + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.ConsumeScrollWheel))] + [HarmonyPrefix] + private static bool Prefix_ConsumeScrollWheel_ItemClass(ItemClass __instance, ItemInventoryData _data, float _scrollWheelInput, PlayerActionsLocal _playerInput, ref bool __result) + { + __result = false; + for (int i = 0; i < __instance.Actions.Length; i++) + { + ItemAction action = __instance.Actions[i]; + if (action != null && action.ConsumeScrollWheel(_data.actionData[i], _scrollWheelInput, _playerInput)) + { + __result = true; + break; + } + + } + return false; + } + #endregion + + //KEEP + #region Create modifier data for more actions + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.CreateInventoryData))] + [HarmonyPostfix] + private static void Postfix_CreateInventoryData_ItemClass(ItemInventoryData __result, ItemClass __instance) + { + int prevCount = __result.actionData.Count; + while (__result.actionData.Count < __instance.Actions.Length) + { + __result.actionData.Add(null); + } + for (; prevCount < __instance.Actions.Length; prevCount++) + { + if (__instance.Actions[prevCount] != null) + __result.actionData[prevCount] = __instance.Actions[prevCount].CreateModifierData(__result, prevCount); + } + } + #endregion + + //todo: should I patch ItemClass.ExecuteAction for melee actions? + + //KEEP + #region IsFocusBlockInside? + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.IsFocusBlockInside))] + [HarmonyPrefix] + private static bool Prefix_IsFocusBlockInside_ItemClass(ItemClass __instance, ref bool __result) + { + __result = __instance.Actions.All(action => action != null && action.IsFocusBlockInside()); + return false; + } + #endregion + + //KEEP + #region IsHUDDisabled + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.IsHUDDisabled))] + [HarmonyPrefix] + private static bool Prefix_IsHUDDisabled_ItemClass(ItemClass __instance, ref bool __result, ItemInventoryData _data) + { + __result = false; + for (int i = 0; i < __instance.Actions.Length; i++) + { + __result |= __instance.Actions[i] != null && __instance.Actions[i].IsHUDDisabled(_data.actionData[i]); + } + return false; + } + #endregion + + //KEEP + #region OnHUD + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.OnHUD))] + [HarmonyPrefix] + private static bool Prefix_OnHUD_ItemClass(ItemInventoryData _data, int _x, int _y, ItemClass __instance) + { + for (int i = 0; i < __instance.Actions.Length; i++) + { + __instance.Actions[i]?.OnHUD(_data.actionData[i], _x, _y); + } + return false; + } + + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.GetCrosshairType))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_GetCrosshairType_ItemClass(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + LocalBuilder lbd_index = generator.DeclareLocal(typeof(int)); + + FieldInfo fld_action = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions)); + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.LoadsField(fld_action) && codes[i + 1].opcode == OpCodes.Ldc_I4_0) + { + codes[i + 1].opcode = OpCodes.Ldloc_S; + codes[i + 1].operand = lbd_index; + } + } + + codes.InsertRange(0, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + CodeInstruction.LoadField(typeof(ItemInventoryData), nameof(ItemInventoryData.holdingEntity)), + CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.GetActionIndexForEntity)), + new CodeInstruction(OpCodes.Stloc_S, lbd_index) + }); + + return codes; + } + #endregion + + //KEEP + #region OnScreenOverlay + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.OnScreenOverlay))] + [HarmonyPrefix] + private static bool Prefix_OnScreenOverlay_ItemClass(ItemInventoryData _data, ItemClass __instance) + { + for (int i = 0; i < __instance.Actions.Length; i++) + { + __instance.Actions[i]?.OnScreenOverlay(_data.actionData[i]); + } + return false; + } + #endregion + + #region inventory related + [HarmonyPatch(typeof(Inventory), nameof(Inventory.GetHoldingGun))] + [HarmonyPrefix] + private static bool Prefix_GetHoldingGun_Inventory(Inventory __instance, ref ItemActionAttack __result) + { + __result = __instance.holdingItem.Actions[MultiActionManager.GetActionIndexForEntity(__instance.entity)] as ItemActionAttack ?? __instance.holdingItem.Actions[0] as ItemActionAttack; + return false; + } + + [HarmonyPatch(typeof(Inventory), nameof(Inventory.GetHoldingDynamicMelee))] + [HarmonyPrefix] + private static bool Prefix_GetHoldingDynamicMelee_Inventory(Inventory __instance, ref ItemActionDynamic __result) + { + __result = __instance.holdingItem.Actions[MultiActionManager.GetActionIndexForEntity(__instance.entity)] as ItemActionDynamic ?? __instance.holdingItem.Actions[0] as ItemActionDynamic; + return false; + } + + //[HarmonyPatch(typeof(Inventory), "clearSlotByIndex")] + //[HarmonyPrefix] + //private static bool Prefix_clearSlotByIndex_Inventory(int _idx, Inventory __instance, EntityAlive ___entity) + //{ + // if (__instance.holdingItemIdx == _idx && ___entity != null && !___entity.isEntityRemote) + // { + // var mapping = MultiActionManager.GetMappingForEntity(___entity.entityId); + // mapping?.SaveMeta(); + // } + // return true; + //} + #endregion + + #region GameManager.ItemReload* + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.SetAmmoType))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SetAmmoType_ItemActionRanged(IEnumerable instructions) + { + var codes = instructions.ToList(); + + MethodInfo mtd_reloadserver = AccessTools.Method(typeof(GameManager), nameof(GameManager.ItemReloadServer)); + + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.Calls(mtd_reloadserver)) + { + codes.RemoveAt(i); + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex)), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.FixedItemReloadServer)) + }); + codes.RemoveAt(i - 3); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.SwapAmmoType))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SwapAmmoType_ItemActionRanged(IEnumerable instructions) + { + var codes = instructions.ToList(); + + MethodInfo mtd_reloadserver = AccessTools.Method(typeof(GameManager), nameof(GameManager.ItemReloadServer)); + FieldInfo fld_actiondata = AccessTools.Field(typeof(ItemInventoryData), nameof(ItemInventoryData.actionData)); + + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.Calls(mtd_reloadserver)) + { + codes.RemoveAt(i); + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex)), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.FixedItemReloadServer)) + }); + codes[i - 4].MoveLabelsFrom(codes[i - 5]); + codes.RemoveAt(i - 5); + break; + } + else if (code.LoadsField(fld_actiondata)) + { + codes.RemoveAt(i + 1); + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex)) + }); + i += 1; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.SwapAmmoType))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SwapAmmoType_ItemActionLauncher(IEnumerable instructions) + { + var codes = instructions.ToList(); + + FieldInfo fld_actiondata = AccessTools.Field(typeof(ItemInventoryData), nameof(ItemInventoryData.actionData)); + + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.LoadsField(fld_actiondata)) + { + codes.RemoveAt(i + 1); + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex)) + }); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.SwapSelectedAmmo))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SwapSelectedAmmo_ItemActionRanged(IEnumerable instructions) + { + var codes = instructions.ToList(); + + MethodInfo mtd_reloadserver = AccessTools.Method(typeof(GameManager), nameof(GameManager.ItemReloadServer)); + MethodInfo mtd_canreload = AccessTools.Method(typeof(ItemActionAttack), nameof(ItemActionAttack.CanReload)); + + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.Calls(mtd_reloadserver)) + { + codes.RemoveAt(i); + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex)), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.FixedItemReloadServer)) + }); + codes.RemoveAt(i - 3); + break; + } + else if (code.Calls(mtd_canreload)) + { + codes.RemoveAt(i - 2); + codes.InsertRange(i - 2, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex)) + }); + codes.RemoveRange(i - 9, 3); + codes.Insert(i - 9, new CodeInstruction(OpCodes.Ldarg_0)); + i--; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.loadNewAmmunition))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_loadNewAmmunition_ItemActionRanged(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var fld_actiondata = AccessTools.Field(typeof(ItemInventoryData), nameof(ItemInventoryData.actionData)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_actiondata)) + { + codes.RemoveAt(i + 1); + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_3), + CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.GetActionIndexForEntity)) + }); + break; + } + } + return codes; + } + #endregion + + //KEEP + #region Launcher logic + #region Launcher projectile meta and action index + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.StartHolding))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_StartHolding_ItemActionLauncher(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + var fld_meta = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.Meta)); + var mtd_delete = AccessTools.Method(typeof(ItemActionLauncher), nameof(ItemActionLauncher.DeleteProjectiles)); + var prop_itemvalue = AccessTools.PropertyGetter(typeof(ItemInventoryData), nameof(ItemInventoryData.itemValue)); + var lbd_meta = generator.DeclareLocal(typeof(int)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_delete)) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)), + new CodeInstruction(OpCodes.Callvirt, prop_itemvalue), + new CodeInstruction(OpCodes.Ldarg_1), + CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.indexInEntityOfAction)), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetMetaByActionIndex)), + new CodeInstruction(OpCodes.Stloc_S, lbd_meta) + }); + i += 7; + } + else if (codes[i].LoadsField(fld_meta)) + { + codes.Insert(i + 1, new CodeInstruction(OpCodes.Ldloc_S, lbd_meta)); + codes.RemoveRange(i - 3, 4); + i -= 3; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.instantiateProjectile))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_instantiateProjectile_ItemActionLauncher_MetaIndex(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var fld_ammoindex = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.SelectedAmmoTypeIndex)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_ammoindex)) + { + codes[i].opcode = OpCodes.Call; + codes[i].operand = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetSelectedAmmoIndexByActionIndex)); + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.indexInEntityOfAction)) + }); + break; + } + } + + return codes; + } + #endregion + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.instantiateProjectile))] + [HarmonyTranspiler] + //use custom script + private static IEnumerable Transpiler_instantiateProjectile_ItemActionLauncher_ReplaceScript(IEnumerable instructions) + { + MethodInfo mtd_addcomponent = AccessTools.Method(typeof(GameObject), nameof(GameObject.AddComponent), Array.Empty()); + MethodInfo mtd_addcomponentprev = mtd_addcomponent.MakeGenericMethod(typeof(ProjectileMoveScript)); + MethodInfo mtd_addcomponentnew = mtd_addcomponent.MakeGenericMethod(typeof(CustomProjectileMoveScript)); + foreach (var code in instructions) + { + if (code.Calls(mtd_addcomponentprev)) + { + Log.Out("replacing launcher projectile script..."); + code.operand = mtd_addcomponentnew; + } + yield return code; + } + } + + //copy ItemValue to projectile + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.instantiateProjectile))] + [HarmonyPostfix] + private static void Postfix_instantiateProjectile_ItemActionLauncher(Transform __result) + { + var script = __result.GetComponent(); + var projectileValue = script.itemValueProjectile; + var launcherValue = script.itemValueLauncher; + projectileValue.Activated = (byte)(Mathf.Clamp01(script.actionData.strainPercent) * byte.MaxValue); + MultiActionUtils.CopyLauncherValueToProjectile(launcherValue, projectileValue, script.actionData.indexInEntityOfAction); + } + + // + [HarmonyPatch(typeof(ProjectileMoveScript), nameof(ProjectileMoveScript.Fire))] + [HarmonyPrefix] + private static bool Prefix_Fire_ProjectileMoveScript(ProjectileMoveScript __instance, Vector3 _idealStartPosition, Vector3 _flyDirection, Entity _firingEntity, int _hmOverride, float _radius) + { + if (_firingEntity is EntityAlive entityAlive) + entityAlive.MinEventContext.ItemActionData = __instance.actionData; + if (__instance is CustomProjectileMoveScript) + { + __instance.ProjectileFire(_idealStartPosition, _flyDirection, _firingEntity, _hmOverride, _radius); + return false; + } + + return true; + } + #endregion + + #endregion + + #region FireEvent patches, set params + //KEEP + #region Ranged ExecuteAction FireEvent params + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.ExecuteAction))] + [HarmonyPrefix] + private static bool Prefix_ExecuteAction_ItemClass(ref int _actionIdx, ItemInventoryData _data, PlayerActionsLocal _playerActions) + { + + if (_actionIdx != 0 || _playerActions == null || !(_data.holdingEntity is EntityPlayerLocal player)) + { + return true; + } + _actionIdx = MultiActionManager.GetActionIndexForEntity(player); + player.MinEventContext.ItemActionData = _data.actionData[_actionIdx]; + return true; + } + + //why? ask TFP the fuck they are doing + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ExecuteAction))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ExecuteAction_ItemActionRanged(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + FieldInfo fld_itemactiondata = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.ItemActionData)); + MethodInfo mtd_reloadserver = AccessTools.Method(typeof(IGameManager), nameof(IGameManager.ItemReloadServer)); + FieldInfo fld_gamemanager = AccessTools.Field(typeof(ItemInventoryData), nameof(ItemInventoryData.gameManager)); + MethodInfo mtd_getkickback = AccessTools.Method(typeof(ItemActionAttack), nameof(ItemActionAttack.GetKickbackForce)); + MethodInfo mtd_getmaxammo = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.GetMaxAmmoCount)); + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.StoresField(fld_itemactiondata)) + { + codes.Insert(i, new CodeInstruction(OpCodes.Ldarg_1)); + codes.RemoveRange(i - 5, 5); + i -= 4; + } + else if (code.Calls(mtd_reloadserver)) + { + int j = i; + while (!codes[j].LoadsField(fld_gamemanager)) + { + j--; + } + codes.RemoveAt(i); + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.indexInEntityOfAction)), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.FixedItemReloadServer)) + }); + codes.RemoveRange(j - 2, 3); + i--; + } + //else if (code.Calls(mtd_getmaxammo)) + //{ + // int j = i + 1; + // for (; j < codes.Count; j++) + // { + // if (codes[j].Calls(mtd_getkickback)) + // { + // break; + // } + // } + // if (j < codes.Count) + // { + // var jumpto = codes[j - 2]; + // var label = generator.DefineLabel(); + // jumpto.labels.Add(label); + // codes.Insert(i - 2, new CodeInstruction(OpCodes.Br_S, label)); + // codes[i - 2].MoveLabelsFrom(codes[i - 1]); + // i++; + // } + //} + } + + return codes; + } + #endregion + + #region ItemAction.CancelAction + [HarmonyPatch(typeof(ItemActionCatapult), nameof(ItemActionCatapult.CancelAction))] + [HarmonyPrefix] + private static bool Prefix_CancelAction_ItemActionCatapult(ItemActionData _actionData) + { + _actionData.invData.holdingEntity.MinEventContext.ItemActionData = _actionData; + return true; + } + #endregion + + #region ItemActionDynamicMelee.Raycast + [HarmonyPatch(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.Raycast))] + [HarmonyPrefix] + private static bool Prefix_Raycast_ItemActionDynamicMelee(ItemActionDynamic.ItemActionDynamicData _actionData) + { + _actionData.invData.holdingEntity.MinEventContext.ItemActionData = _actionData; + return true; + } + #endregion + + #region Inventory.FireEvent, set current action + [HarmonyPatch(typeof(Inventory), nameof(Inventory.FireEvent))] + [HarmonyPrefix] + private static bool Prefix_FireEvent_Inventory(Inventory __instance) + { + MultiActionUtils.SetMinEventParamsByEntityInventory(__instance.entity); + return true; + } + #endregion + + #region Inventory.syncHeldItem, set current action + [HarmonyPatch(typeof(Inventory), nameof(Inventory.syncHeldItem))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_syncHeldItem_Inventory(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_test = AccessTools.Method(typeof(FastTags), nameof(FastTags.Test_AnySet)); + var fld_itemvalue = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.ItemValue)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].StoresField(fld_itemvalue) && codes[i - 7].Calls(mtd_test)) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(Inventory), nameof(Inventory.entity)), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.SetMinEventParamsByEntityInventory)) + }); + break; + } + } + + return codes; + } + #endregion + + #region ItemValue.FireEvent, read current action + [HarmonyPatch(typeof(ItemValue), nameof(ItemValue.FireEvent))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_FireEvent_ItemValue(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + LocalBuilder lbd_index = generator.DeclareLocal(typeof(int)); + + FieldInfo fld_action = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions)); + FieldInfo fld_ammoindex = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.SelectedAmmoTypeIndex)); + MethodInfo mtd_fireevent = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.FireEvent)); + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.LoadsField(fld_action) && codes[i + 1].opcode == OpCodes.Ldc_I4_0) + { + codes[i + 1].opcode = OpCodes.Ldloc_S; + codes[i + 1].operand = lbd_index; + if (codes[i - 9].opcode == OpCodes.Ret) + { + codes.InsertRange(i - 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_2), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetActionIndexByEventParams)), + new CodeInstruction(OpCodes.Stloc_S, lbd_index) + }); + i += 3; + } + } + else if (code.LoadsField(fld_ammoindex)) + { + code.opcode = OpCodes.Call; + code.operand = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetSelectedAmmoIndexByActionIndex)); + codes.Insert(i, new CodeInstruction(OpCodes.Ldloc_S, lbd_index)); + i++; + } + //action exclude mods + else if (code.Calls(mtd_fireevent) && codes[i + 1].opcode != OpCodes.Ldloc_0) + { + for (int j = i; j >= 0; j--) + { + if (codes[j].opcode == OpCodes.Brfalse_S || codes[j].opcode == OpCodes.Brfalse) + { + var label = codes[j].operand; + codes.InsertRange(j + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemValue), nameof(ItemValue.type)), + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, codes[j + 2].operand), + new CodeInstruction(codes[j + 3].opcode, codes[j + 3].operand), + new CodeInstruction(OpCodes.Ldelem_Ref), + CodeInstruction.LoadField(typeof(ItemValue), nameof(ItemValue.type)), + new CodeInstruction(OpCodes.Ldloc_S, lbd_index), + CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ShouldExcludeTrigger)), + new CodeInstruction(OpCodes.Brtrue_S, label) + }); + i += 10; + break; + } + } + } + } + + return codes; + } + #endregion + + //onSelfEquipStop, onSelfHoldingItemCreated, onSelfEquipStart are not available for individual action, + + //some are already set in update or execute action + + #endregion + + #region EffectManager.GetValue patches, set params + //set correct action index for ItemValue + [HarmonyPatch(typeof(ItemValue), nameof(ItemValue.ModifyValue))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ModifyValue_ItemValue(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + LocalBuilder lbd_index = generator.DeclareLocal(typeof(int)); + + FieldInfo fld_action = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions)); + FieldInfo fld_ammoindex = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.SelectedAmmoTypeIndex)); + FieldInfo fld_mods = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.Modifications)); + FieldInfo fld_cos = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.CosmeticMods)); + MethodInfo mtd_modify = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.ModifyValue)); + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.opcode == OpCodes.Stloc_1) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetActionIndexByEntityEventParams)), + new CodeInstruction(OpCodes.Stloc_S, lbd_index) + }); + } + else if (code.LoadsField(fld_action) && codes[i + 1].opcode == OpCodes.Ldc_I4_0) + { + codes[i + 1].opcode = OpCodes.Ldloc_S; + codes[i + 1].operand = lbd_index; + } + else if (code.LoadsField(fld_ammoindex)) + { + code.opcode = OpCodes.Call; + code.operand = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetSelectedAmmoIndexByActionIndex)); + codes.Insert(i, new CodeInstruction(OpCodes.Ldloc_S, lbd_index)); + i++; + } + else if (code.Calls(mtd_modify)) + { + for (int j = i; j >= 0; j--) + { + if (codes[j].opcode == OpCodes.Brfalse_S || codes[j].opcode == OpCodes.Brfalse) + { + var label = codes[j].operand; + codes.InsertRange(j + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemValue), nameof(ItemValue.type)), + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, codes[j + 2].operand), + new CodeInstruction(codes[j + 3].opcode, codes[j + 3].operand), + new CodeInstruction(OpCodes.Ldelem_Ref), + CodeInstruction.LoadField(typeof(ItemValue), nameof(ItemValue.type)), + new CodeInstruction(OpCodes.Ldloc_S, lbd_index), + CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ShouldExcludePassive)), + new CodeInstruction(OpCodes.Brtrue_S, label) + }); + i += 10; + break; + } + } + } + } + + return codes; + } + + //only current mode should execute OnHUD + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.OnHUD))] + [HarmonyPrefix] + private static bool Prefix_OnHUD_EntityPlayerLocal(EntityPlayerLocal __instance, out ItemActionData __state) + { + __state = __instance.MinEventContext.ItemActionData; + MultiActionUtils.SetMinEventParamsByEntityInventory(__instance); + return true; + } + + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.OnHUD))] + [HarmonyPostfix] + private static void Postfix_OnHUD_EntityPlayerLocal(EntityPlayerLocal __instance, ItemActionData __state) + { + __instance.MinEventContext.ItemActionData = __state; + } + + //for passive value calc + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.guiDrawCrosshair))] + [HarmonyPrefix] + private static bool Prefix_guiDrawCrosshair_EntityPlayerLocal(EntityPlayerLocal __instance) + { + MultiActionUtils.SetMinEventParamsByEntityInventory(__instance); + return true; + } + + //draw crosshair for current action + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.guiDrawCrosshair))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_guiDrawCrosshair_EntityPlayerLocal(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + LocalBuilder lbd_index = generator.DeclareLocal(typeof(int)); + + FieldInfo fld_actiondata = AccessTools.Field(typeof(ItemInventoryData), nameof(ItemInventoryData.actionData)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Stloc_1) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.GetActionIndexForEntity)), + new CodeInstruction(OpCodes.Stloc_S, lbd_index) + }); + i += 3; + } + else if (codes[i].LoadsField(fld_actiondata) && codes[i + 1].opcode == OpCodes.Ldc_I4_0) + { + codes[i + 1].opcode = OpCodes.Ldloc_S; + codes[i + 1].operand = lbd_index; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemAction), nameof(ItemAction.ExecuteBuffActions))] + [HarmonyPrefix] + private static bool Prefix_ExecuteBuffActions_ItemAction(int instigatorId, out (EntityAlive entity, ItemActionData actionData) __state) + { + __state = default; + EntityAlive entity = GameManager.Instance.World.GetEntity(instigatorId) as EntityAlive; + if (entity != null) + { + __state.entity = entity; + __state.actionData = entity.MinEventContext.ItemActionData; + MultiActionUtils.SetMinEventParamsByEntityInventory(entity); + } + else + return false; + return true; + } + + [HarmonyPatch(typeof(ItemAction), nameof(ItemAction.ExecuteBuffActions))] + [HarmonyPostfix] + private static void Postfix_ExecuteBuffActions_ItemAction((EntityAlive entity, ItemActionData actionData) __state, bool __runOriginal) + { + if (__runOriginal && __state.entity != null) + __state.entity.MinEventContext.ItemActionData = __state.actionData; + } + + //ItemAction.GetDismemberChance already set + //ItemActionDynamic.GetExecuteActionTarget not needed + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ItemActionEffects))] + [HarmonyPrefix] + private static bool Prefix_ItemActionEffects_ItemActionLauncher(ItemActionData _actionData, out ItemActionData __state) + { + __state = _actionData.invData.holdingEntity.MinEventContext.ItemActionData; + _actionData.invData.holdingEntity.MinEventContext.ItemActionData = _actionData; + return true; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ItemActionEffects))] + [HarmonyPostfix] + private static void Postfix_ItemActionEffects_ItemActionLauncher(ItemActionData _actionData, ItemActionData __state) + { + _actionData.invData.holdingEntity.MinEventContext.ItemActionData = __state; + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.ClampAmmoCount))] + [HarmonyPrefix] + private static bool Prefix_ClampAmmoCount_ItemActionLauncher(ItemActionLauncher.ItemActionDataLauncher actionData, out ItemActionData __state) + { + __state = actionData.invData.holdingEntity.MinEventContext.ItemActionData; + actionData.invData.holdingEntity.MinEventContext.ItemActionData = actionData; + return true; + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemActionLauncher.ClampAmmoCount))] + [HarmonyPostfix] + private static void Postfix_ClampAmmoCount_ItemActionLauncher(ItemActionLauncher.ItemActionDataLauncher actionData, ItemActionData __state) + { + actionData.invData.holdingEntity.MinEventContext.ItemActionData = __state; + } + #endregion + + #region EffectManager.GetValuesAndSources patches, set params + + [HarmonyPatch(typeof(EntityStats), nameof(EntityStats.Update))] + [HarmonyPrefix] + private static bool Prefix_Update_EntityStats(EntityStats __instance) + { + MultiActionUtils.SetMinEventParamsByEntityInventory(__instance.m_entity); + return true; + } + + //set correct action index for ItemValue + [HarmonyPatch(typeof(ItemValue), nameof(ItemValue.GetModifiedValueData))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_GetModifiedValueData_ItemValue(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + LocalBuilder lbd_index = generator.DeclareLocal(typeof(int)); + + FieldInfo fld_action = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions)); + FieldInfo fld_ammoindex = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.SelectedAmmoTypeIndex)); + FieldInfo fld_mods = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.Modifications)); + FieldInfo fld_cos = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.CosmeticMods)); + MethodInfo mtd_getvalue = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.GetModifiedValueData)); + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.opcode == OpCodes.Stloc_0) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_3), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetActionIndexByEntityEventParams)), + new CodeInstruction(OpCodes.Stloc_S, lbd_index) + }); + } + else if (code.LoadsField(fld_action) && codes[i + 1].opcode == OpCodes.Ldc_I4_0) + { + codes[i + 1].opcode = OpCodes.Ldloc_S; + codes[i + 1].operand = lbd_index; + } + else if (code.LoadsField(fld_ammoindex)) + { + code.opcode = OpCodes.Call; + code.operand = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetSelectedAmmoIndexByActionIndex)); + codes.Insert(i, new CodeInstruction(OpCodes.Ldloc_S, lbd_index)); + i++; + } + else if (code.Calls(mtd_getvalue) && codes[i + 1].opcode != OpCodes.Ldloc_0) + { + for (int j = i; j >= 0; j--) + { + if (codes[j].opcode == OpCodes.Brfalse_S || codes[j].opcode == OpCodes.Brfalse) + { + var label = codes[j].operand; + codes.InsertRange(j + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemValue), nameof(ItemValue.type)), + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, codes[j + 2].operand), + new CodeInstruction(codes[j + 3].opcode, codes[j + 3].operand), + new CodeInstruction(OpCodes.Ldelem_Ref), + CodeInstruction.LoadField(typeof(ItemValue), nameof(ItemValue.type)), + new CodeInstruction(OpCodes.Ldloc_S, lbd_index), + CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ShouldExcludePassive)), + new CodeInstruction(OpCodes.Brtrue_S, label) + }); + i += 10; + break; + } + } + } + } + + return codes; + } + #endregion + + //KEEP + #region Misc + //load correct property for melee + [HarmonyPatch(typeof(AnimatorMeleeAttackState), nameof(AnimatorMeleeAttackState.OnStateEnter))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_OnStateEnter_AnimatorMeleeAttackState(IEnumerable instructions) + { + var codes = instructions.ToList(); + var fld_actionindex = AccessTools.Field(typeof(AnimatorMeleeAttackState), nameof(AnimatorMeleeAttackState.actionIndex)); + MethodInfo mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue)); + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.LoadsField(fld_actionindex) && codes[i + 2].opcode == OpCodes.Ldstr) + { + string property = codes[i + 2].operand.ToString(); + property = property.Split('.')[1]; + codes.RemoveRange(i + 1, 4); + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldstr, property), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetPropertyName)) + }); + i -= 2; + } + else if (code.Calls(mtd_getvalue)) + { + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(AnimatorMeleeAttackState), "entity"), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(AnimatorMeleeAttackState), "actionIndex"), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.SetMinEventParamsActionData)) + }); + i += 5; + } + } + + return codes; + } + + //make sure it's set to current action after for loop + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.OnHoldingUpdate))] + [HarmonyPostfix] + private static void Postfix_OnHoldingUpdate_ItemClass(ItemInventoryData _data) + { + MultiActionUtils.SetMinEventParamsByEntityInventory(_data.holdingEntity); + } + + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.StopHolding))] + [HarmonyPostfix] + private static void Postfix_StopHolding_ItemClass(ItemInventoryData _data) + { + if (_data.holdingEntity != null) + { + MultiActionUtils.SetMinEventParamsByEntityInventory(_data.holdingEntity); + MultiActionManager.SetMappingForEntity(_data.holdingEntity.entityId, null); + } + } + + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.StartHolding))] + [HarmonyPostfix] + private static void Postfix_StartHolding_ItemClass(ItemInventoryData _data) + { + MultiActionUtils.SetMinEventParamsByEntityInventory(_data.holdingEntity); + } + + //should be fixed in Harmony 2.12.0.0 + //[HarmonyPatch(typeof(ItemClassesFromXml), nameof(ItemClassesFromXml.parseItem))] + //[HarmonyPrefix] + //private static bool Prefix_parseItem_ItemClassesFromXml(XElement _node) + //{ + // DynamicProperties dynamicProperties = new DynamicProperties(); + // string attribute = _node.GetAttribute("name"); + // if (attribute.Length == 0) + // { + // throw new Exception("Attribute 'name' missing on item"); + // } + // //here + // List[] array = new List[ItemClass.cMaxActionNames]; + // for (int i = 0; i < array.Length; i++) + // { + // array[i] = new List(); + // } + + // foreach (XElement item in _node.Elements("property")) + // { + // dynamicProperties.Add(item); + // string attribute2 = item.GetAttribute("class"); + // if (attribute2.StartsWith("Action")) + // { + // int num = attribute2[attribute2.Length - 1] - '0'; + // array[num].AddRange(RequirementBase.ParseRequirements(item)); + // } + // } + + // if (dynamicProperties.Values.ContainsKey("Extends")) + // { + // string text = dynamicProperties.Values["Extends"]; + // ItemClass itemClass = ItemClass.GetItemClass(text); + // if (itemClass == null) + // { + // throw new Exception($"Extends item {text} is not specified for item {attribute}'"); + // } + + // HashSet hashSet = new HashSet { Block.PropCreativeMode }; + // if (dynamicProperties.Params1.ContainsKey("Extends")) + // { + // string[] array2 = dynamicProperties.Params1["Extends"].Split(new[] { ',' }, StringSplitOptions.None); + // foreach (string text2 in array2) + // { + // hashSet.Add(text2.Trim()); + // } + // } + + // DynamicProperties dynamicProperties2 = new DynamicProperties(); + // dynamicProperties2.CopyFrom(itemClass.Properties, hashSet); + // dynamicProperties2.CopyFrom(dynamicProperties); + // dynamicProperties = dynamicProperties2; + // } + + // ItemClass itemClass2; + // if (dynamicProperties.Values.ContainsKey("Class")) + // { + // string text3 = dynamicProperties.Values["Class"]; + // if (!text3.Contains(",")) + // { + // text3 += ",Assembly-CSharp"; + // } + // try + // { + // itemClass2 = (ItemClass)Activator.CreateInstance(Type.GetType(text3)); + // } + // catch (Exception) + // { + // throw new Exception("No item class '" + text3 + " found!"); + // } + // } + // else + // { + // itemClass2 = new ItemClass(); + // } + + // itemClass2.Properties = dynamicProperties; + // if (dynamicProperties.Params1.ContainsKey("Extends")) + // { + // string text4 = dynamicProperties.Values["Extends"]; + // if (ItemClass.GetItemClass(text4) == null) + // { + // throw new Exception($"Extends item {text4} is not specified for item {attribute}'"); + // } + // } + + // itemClass2.Effects = MinEffectController.ParseXml(_node, null, MinEffectController.SourceParentType.ItemClass, itemClass2.Id); + // itemClass2.SetName(attribute); + // itemClass2.setLocalizedItemName(Localization.Get(attribute)); + // if (dynamicProperties.Values.ContainsKey("Stacknumber")) + // { + // itemClass2.Stacknumber = new DataItem(int.Parse(dynamicProperties.Values["Stacknumber"])); + // } + // else + // { + // itemClass2.Stacknumber = new DataItem(500); + // } + + // if (dynamicProperties.Values.ContainsKey("Canhold")) + // { + // itemClass2.SetCanHold(StringParsers.ParseBool(dynamicProperties.Values["Canhold"])); + // } + + // if (dynamicProperties.Values.ContainsKey("Candrop")) + // { + // itemClass2.SetCanDrop(StringParsers.ParseBool(dynamicProperties.Values["Candrop"])); + // } + + // if (!dynamicProperties.Values.ContainsKey("Material")) + // { + // throw new Exception("Attribute 'material' missing on item '" + attribute + "'"); + // } + + // itemClass2.MadeOfMaterial = MaterialBlock.fromString(dynamicProperties.Values["Material"]); + // if (itemClass2.MadeOfMaterial == null) + // { + // throw new Exception("Attribute 'material' '" + dynamicProperties.Values["Material"] + "' refers to not existing material in item '" + attribute + "'"); + // } + + // if (!dynamicProperties.Values.ContainsKey("Meshfile") && itemClass2.CanHold()) + // { + // throw new Exception("Attribute 'Meshfile' missing on item '" + attribute + "'"); + // } + + // itemClass2.MeshFile = dynamicProperties.Values["Meshfile"]; + // DataLoader.PreloadBundle(itemClass2.MeshFile); + // StringParsers.TryParseFloat(dynamicProperties.Values["StickyOffset"], out itemClass2.StickyOffset); + // StringParsers.TryParseFloat(dynamicProperties.Values["StickyColliderRadius"], out itemClass2.StickyColliderRadius); + // StringParsers.TryParseSInt32(dynamicProperties.Values["StickyColliderUp"], out itemClass2.StickyColliderUp); + // StringParsers.TryParseFloat(dynamicProperties.Values["StickyColliderLength"], out itemClass2.StickyColliderLength); + // itemClass2.StickyMaterial = dynamicProperties.Values["StickyMaterial"]; + // if (dynamicProperties.Values.ContainsKey("ImageEffectOnActive")) + // { + // itemClass2.ImageEffectOnActive = new DataItem(dynamicProperties.Values["ImageEffectOnActive"]); + // } + + // if (dynamicProperties.Values.ContainsKey("Active")) + // { + // itemClass2.Active = new DataItem(_startValue: false); + // } + + // if (dynamicProperties.Values.ContainsKey(ItemClass.PropIsSticky)) + // { + // itemClass2.IsSticky = StringParsers.ParseBool(dynamicProperties.Values[ItemClass.PropIsSticky]); + // } + + // if (dynamicProperties.Values.ContainsKey("DropMeshfile") && itemClass2.CanHold()) + // { + // itemClass2.DropMeshFile = dynamicProperties.Values["DropMeshfile"]; + // DataLoader.PreloadBundle(itemClass2.DropMeshFile); + // } + + // if (dynamicProperties.Values.ContainsKey("HandMeshfile") && itemClass2.CanHold()) + // { + // itemClass2.HandMeshFile = dynamicProperties.Values["HandMeshfile"]; + // DataLoader.PreloadBundle(itemClass2.HandMeshFile); + // } + + // if (dynamicProperties.Values.ContainsKey("HoldType")) + // { + // string s = dynamicProperties.Values["HoldType"]; + // int result = 0; + // if (!int.TryParse(s, out result)) + // { + // throw new Exception("Cannot parse attribute hold_type for item '" + attribute + "'"); + // } + + // itemClass2.HoldType = new DataItem(result); + // } + + // if (dynamicProperties.Values.ContainsKey("RepairTools")) + // { + // string[] array3 = dynamicProperties.Values["RepairTools"].Replace(" ", "").Split(new[] { ',' }, StringSplitOptions.None); + // DataItem[] array4 = new DataItem[array3.Length]; + // for (int k = 0; k < array3.Length; k++) + // { + // array4[k] = new DataItem(array3[k]); + // } + + // itemClass2.RepairTools = new ItemData.DataItemArrayRepairTools(array4); + // } + + // if (dynamicProperties.Values.ContainsKey("RepairAmount")) + // { + // int result2 = 0; + // int.TryParse(dynamicProperties.Values["RepairAmount"], out result2); + // itemClass2.RepairAmount = new DataItem(result2); + // } + + // if (dynamicProperties.Values.ContainsKey("RepairTime")) + // { + // float _result = 0f; + // StringParsers.TryParseFloat(dynamicProperties.Values["RepairTime"], out _result); + // itemClass2.RepairTime = new DataItem(_result); + // } + // else if (itemClass2.RepairAmount != null) + // { + // itemClass2.RepairTime = new DataItem(1f); + // } + + // if (dynamicProperties.Values.ContainsKey("Degradation")) + // { + // itemClass2.MaxUseTimes = new DataItem(int.Parse(dynamicProperties.Values["Degradation"])); + // } + // else + // { + // itemClass2.MaxUseTimes = new DataItem(0); + // itemClass2.MaxUseTimesBreaksAfter = new DataItem(_startValue: false); + // } + + // if (dynamicProperties.Values.ContainsKey("DegradationBreaksAfter")) + // { + // itemClass2.MaxUseTimesBreaksAfter = new DataItem(StringParsers.ParseBool(dynamicProperties.Values["DegradationBreaksAfter"])); + // } + // else if (dynamicProperties.Values.ContainsKey("Degradation")) + // { + // itemClass2.MaxUseTimesBreaksAfter = new DataItem(_startValue: true); + // } + + // if (dynamicProperties.Values.ContainsKey("EconomicValue")) + // { + // itemClass2.EconomicValue = StringParsers.ParseFloat(dynamicProperties.Values["EconomicValue"]); + // } + + // if (dynamicProperties.Classes.ContainsKey("Preview")) + // { + // DynamicProperties dynamicProperties3 = dynamicProperties.Classes["Preview"]; + // itemClass2.Preview = new PreviewData(); + // if (dynamicProperties3.Values.ContainsKey("Zoom")) + // { + // itemClass2.Preview.Zoom = new DataItem(int.Parse(dynamicProperties3.Values["Zoom"])); + // } + + // if (dynamicProperties3.Values.ContainsKey("Pos")) + // { + // itemClass2.Preview.Pos = new DataItem(StringParsers.ParseVector2(dynamicProperties3.Values["Pos"])); + // } + // else + // { + // itemClass2.Preview.Pos = new DataItem(Vector2.zero); + // } + + // if (dynamicProperties3.Values.ContainsKey("Rot")) + // { + // itemClass2.Preview.Rot = new DataItem(StringParsers.ParseVector3(dynamicProperties3.Values["Rot"])); + // } + // else + // { + // itemClass2.Preview.Rot = new DataItem(Vector3.zero); + // } + // } + + // for (int l = 0; l < itemClass2.Actions.Length; l++) + // { + // string text5 = ItemClass.itemActionNames[l]; + // if (dynamicProperties.Classes.ContainsKey(text5)) + // { + // if (!dynamicProperties.Values.ContainsKey(text5 + ".Class")) + // { + // throw new Exception("No class attribute found on " + text5 + " in item with '" + attribute + "'"); + // } + + // string text6 = dynamicProperties.Values[text5 + ".Class"]; + // ItemAction itemAction; + // try + // { + // itemAction = (ItemAction)Activator.CreateInstance(ReflectionHelpers.GetTypeWithPrefix("ItemAction", text6)); + // } + // catch (Exception) + // { + // throw new Exception("ItemAction class '" + text6 + " could not be instantiated"); + // } + + // itemAction.item = itemClass2; + // itemAction.ActionIndex = l; + // itemAction.ReadFrom(dynamicProperties.Classes[text5]); + // if (array[l].Count > 0) + // { + // itemAction.ExecutionRequirements = array[l]; + // } + + // itemClass2.Actions[l] = itemAction; + // } + // } + + // itemClass2.Init(); + // return false; + //} + + /// + /// fix requirement array count + /// + /// + /// + [HarmonyPatch(typeof(ItemClassesFromXml), nameof(ItemClassesFromXml.parseItem))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_parseItem_ItemClassesFromXml(IEnumerable instructions) + { + bool isLastInsThrow = false; + foreach (var code in instructions) + { + if (isLastInsThrow) + { + isLastInsThrow = false; + if (code.opcode == OpCodes.Ldc_I4_3) + { + code.opcode = OpCodes.Ldc_I4_5; + } + } + if (code.opcode == OpCodes.Throw) + { + isLastInsThrow = true; + } + yield return code; + } + } + + [HarmonyPatch(typeof(ItemModificationsFromXml), nameof(ItemModificationsFromXml.parseItem))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_parseItem_ItemModificationsFromXml(IEnumerable instructions) + { + var codes = instructions.ToList(); + + for (int i = 0; i < codes.Count - 1; i++) + { + if (codes[i].opcode == OpCodes.Ldc_I4_3 && codes[i + 1].opcode == OpCodes.Newarr) + { + codes[i].opcode = OpCodes.Ldc_I4_5; + break; + } + } + return codes; + } + + /* + [HarmonyPatch(typeof(ItemClassesFromXml), nameof(ItemClassesFromXml.parseItem))] + [HarmonyPrefix] + private static bool Prefix_parseItem_ItemClassesFromXml(XElement _node) + { + //throw new Exception("Exception thrown from here!"); + DynamicProperties dynamicProperties = new DynamicProperties(); + string attribute = _node.GetAttribute("name"); + if (attribute.Length == 0) + { + throw new Exception("Attribute 'name' missing on item"); + } + //Log.Out($"Parsing item {attribute}..."); + List[] array = new List[5]; + for (int i = 0; i < array.Length; i++) + { + array[i] = new List(); + } + + foreach (XElement item in _node.Elements("property")) + { + dynamicProperties.Add(item); + string attribute2 = item.GetAttribute("class"); + if (attribute2.StartsWith("Action")) + { + int num = attribute2[attribute2.Length - 1] - 48; + array[num].AddRange(RequirementBase.ParseRequirements(item)); + } + } + + if (dynamicProperties.Values.ContainsKey("Extends")) + { + string text = dynamicProperties.Values["Extends"]; + ItemClass itemClass = ItemClass.GetItemClass(text); + if (itemClass == null) + { + throw new Exception($"Extends item {text} is not specified for item {attribute}'"); + } + + HashSet hashSet = new HashSet { Block.PropCreativeMode }; + if (dynamicProperties.Params1.ContainsKey("Extends")) + { + string[] array2 = dynamicProperties.Params1["Extends"].Split(','); + foreach (string text2 in array2) + { + hashSet.Add(text2.Trim()); + } + } + + DynamicProperties dynamicProperties2 = new DynamicProperties(); + dynamicProperties2.CopyFrom(itemClass.Properties, hashSet); + dynamicProperties2.CopyFrom(dynamicProperties); + dynamicProperties = dynamicProperties2; + } + + ItemClass itemClass2; + if (dynamicProperties.Values.ContainsKey("Class")) + { + string text3 = dynamicProperties.Values["Class"]; + if (!text3.Contains(",")) + { + text3 += ",Assembly-CSharp"; + } + try + { + itemClass2 = (ItemClass)Activator.CreateInstance(Type.GetType(text3)); + } + catch (Exception) + { + throw new Exception("No item class '" + text3 + "' found!"); + } + } + else + { + itemClass2 = new ItemClass(); + } + + itemClass2.Properties = dynamicProperties; + if (dynamicProperties.Params1.ContainsKey("Extends")) + { + string text4 = dynamicProperties.Values["Extends"]; + if (ItemClass.GetItemClass(text4) == null) + { + throw new Exception($"Extends item {text4} is not specified for item {attribute}'"); + } + } + + itemClass2.Effects = MinEffectController.ParseXml(_node, null, MinEffectController.SourceParentType.ItemClass, itemClass2.Id); + itemClass2.SetName(attribute); + itemClass2.setLocalizedItemName(Localization.Get(attribute)); + if (dynamicProperties.Values.ContainsKey("Stacknumber")) + { + itemClass2.Stacknumber = new DataItem(int.Parse(dynamicProperties.Values["Stacknumber"])); + } + else + { + itemClass2.Stacknumber = new DataItem(500); + } + + if (dynamicProperties.Values.ContainsKey("Canhold")) + { + itemClass2.SetCanHold(StringParsers.ParseBool(dynamicProperties.Values["Canhold"])); + } + + if (dynamicProperties.Values.ContainsKey("Candrop")) + { + itemClass2.SetCanDrop(StringParsers.ParseBool(dynamicProperties.Values["Candrop"])); + } + + if (!dynamicProperties.Values.ContainsKey("Material")) + { + throw new Exception("Attribute 'material' missing on item '" + attribute + "'"); + } + + itemClass2.MadeOfMaterial = MaterialBlock.fromString(dynamicProperties.Values["Material"]); + if (itemClass2.MadeOfMaterial == null) + { + throw new Exception("Attribute 'material' '" + dynamicProperties.Values["Material"] + "' refers to not existing material in item '" + attribute + "'"); + } + + if (!dynamicProperties.Values.ContainsKey("Meshfile") && itemClass2.CanHold()) + { + throw new Exception("Attribute 'Meshfile' missing on item '" + attribute + "'"); + } + + itemClass2.MeshFile = dynamicProperties.Values["Meshfile"]; + DataLoader.PreloadBundle(itemClass2.MeshFile); + StringParsers.TryParseFloat(dynamicProperties.Values["StickyOffset"], out itemClass2.StickyOffset); + StringParsers.TryParseFloat(dynamicProperties.Values["StickyColliderRadius"], out itemClass2.StickyColliderRadius); + StringParsers.TryParseSInt32(dynamicProperties.Values["StickyColliderUp"], out itemClass2.StickyColliderUp); + StringParsers.TryParseFloat(dynamicProperties.Values["StickyColliderLength"], out itemClass2.StickyColliderLength); + itemClass2.StickyMaterial = dynamicProperties.Values["StickyMaterial"]; + if (dynamicProperties.Values.ContainsKey("ImageEffectOnActive")) + { + itemClass2.ImageEffectOnActive = new DataItem(dynamicProperties.Values["ImageEffectOnActive"]); + } + + if (dynamicProperties.Values.ContainsKey("Active")) + { + itemClass2.Active = new DataItem(_startValue: false); + } + + if (dynamicProperties.Values.ContainsKey(ItemClass.PropIsSticky)) + { + itemClass2.IsSticky = StringParsers.ParseBool(dynamicProperties.Values[ItemClass.PropIsSticky]); + } + + if (dynamicProperties.Values.ContainsKey("DropMeshfile") && itemClass2.CanHold()) + { + itemClass2.DropMeshFile = dynamicProperties.Values["DropMeshfile"]; + DataLoader.PreloadBundle(itemClass2.DropMeshFile); + } + + if (dynamicProperties.Values.ContainsKey("HandMeshfile") && itemClass2.CanHold()) + { + itemClass2.HandMeshFile = dynamicProperties.Values["HandMeshfile"]; + DataLoader.PreloadBundle(itemClass2.HandMeshFile); + } + + if (dynamicProperties.Values.ContainsKey("HoldType")) + { + string s = dynamicProperties.Values["HoldType"]; + int result = 0; + if (!int.TryParse(s, out result)) + { + throw new Exception("Cannot parse attribute hold_type for item '" + attribute + "'"); + } + + itemClass2.HoldType = new DataItem(result); + } + + if (dynamicProperties.Values.ContainsKey("RepairTools")) + { + string[] array3 = dynamicProperties.Values["RepairTools"].Replace(" ", "").Split(','); + DataItem[] array4 = new DataItem[array3.Length]; + for (int k = 0; k < array3.Length; k++) + { + array4[k] = new DataItem(array3[k]); + } + + itemClass2.RepairTools = new ItemData.DataItemArrayRepairTools(array4); + } + + if (dynamicProperties.Values.ContainsKey("RepairAmount")) + { + int result2 = 0; + int.TryParse(dynamicProperties.Values["RepairAmount"], out result2); + itemClass2.RepairAmount = new DataItem(result2); + } + + if (dynamicProperties.Values.ContainsKey("RepairTime")) + { + float _result = 0f; + StringParsers.TryParseFloat(dynamicProperties.Values["RepairTime"], out _result); + itemClass2.RepairTime = new DataItem(_result); + } + else if (itemClass2.RepairAmount != null) + { + itemClass2.RepairTime = new DataItem(1f); + } + + if (dynamicProperties.Values.ContainsKey("Degradation")) + { + itemClass2.MaxUseTimes = new DataItem(int.Parse(dynamicProperties.Values["Degradation"])); + } + else + { + itemClass2.MaxUseTimes = new DataItem(0); + itemClass2.MaxUseTimesBreaksAfter = new DataItem(_startValue: false); + } + + if (dynamicProperties.Values.ContainsKey("DegradationBreaksAfter")) + { + itemClass2.MaxUseTimesBreaksAfter = new DataItem(StringParsers.ParseBool(dynamicProperties.Values["DegradationBreaksAfter"])); + } + else if (dynamicProperties.Values.ContainsKey("Degradation")) + { + itemClass2.MaxUseTimesBreaksAfter = new DataItem(_startValue: true); + } + + if (dynamicProperties.Values.ContainsKey("EconomicValue")) + { + itemClass2.EconomicValue = StringParsers.ParseFloat(dynamicProperties.Values["EconomicValue"]); + } + + if (dynamicProperties.Classes.ContainsKey("Preview")) + { + DynamicProperties dynamicProperties3 = dynamicProperties.Classes["Preview"]; + itemClass2.Preview = new PreviewData(); + if (dynamicProperties3.Values.ContainsKey("Zoom")) + { + itemClass2.Preview.Zoom = new DataItem(int.Parse(dynamicProperties3.Values["Zoom"])); + } + + if (dynamicProperties3.Values.ContainsKey("Pos")) + { + itemClass2.Preview.Pos = new DataItem(StringParsers.ParseVector2(dynamicProperties3.Values["Pos"])); + } + else + { + itemClass2.Preview.Pos = new DataItem(Vector2.zero); + } + + if (dynamicProperties3.Values.ContainsKey("Rot")) + { + itemClass2.Preview.Rot = new DataItem(StringParsers.ParseVector3(dynamicProperties3.Values["Rot"])); + } + else + { + itemClass2.Preview.Rot = new DataItem(Vector3.zero); + } + } + + for (int l = 0; l < itemClass2.Actions.Length; l++) + { + string text5 = ItemClass.itemActionNames[l]; + if (dynamicProperties.Classes.ContainsKey(text5)) + { + if (!dynamicProperties.Values.ContainsKey(text5 + ".Class")) + { + throw new Exception("No class attribute found on " + text5 + " in item with '" + attribute + "'"); + } + + string text6 = dynamicProperties.Values[text5 + ".Class"]; + ItemAction itemAction; + try + { + itemAction = (ItemAction)Activator.CreateInstance(ReflectionHelpers.GetTypeWithPrefix("ItemAction", text6)); + } + catch (Exception) + { + throw new Exception("ItemAction class '" + text6 + " could not be instantiated"); + } + + itemAction.item = itemClass2; + itemAction.ActionIndex = l; + itemAction.ReadFrom(dynamicProperties.Classes[text5]); + if (array[l].Count > 0) + { + itemAction.ExecutionRequirements = array[l]; + } + + itemClass2.Actions[l] = itemAction; + } + } + + itemClass2.Init(); + return false; + } + */ + + [HarmonyPatch(typeof(Inventory), nameof(Inventory.onInventoryChanged))] + [HarmonyPrefix] + private static bool Prefix_onInventoryChanged_Inventory(Inventory __instance) + { + if (__instance.entity != null) + MultiActionManager.UpdateLocalMetaSave(__instance.entity.entityId); + return true; + } + #endregion + + //KEEP + #region Action mode handling + [HarmonyPatch(typeof(NetPackagePlayerStats), nameof(NetPackagePlayerStats.ProcessPackage))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ProcessPackage_NetPackagePlayerStats(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var fld_entityid = AccessTools.Field(typeof(NetPackagePlayerStats), nameof(NetPackagePlayerStats.entityId)); + var fld_itemstack = AccessTools.Field(typeof(NetPackagePlayerStats), nameof(NetPackagePlayerStats.holdingItemStack)); + codes.InsertRange(codes.Count - 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, fld_entityid), + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, fld_itemstack), + CodeInstruction.Call(typeof(MultiActionPatches), nameof(CheckItemValueMode)) + }); + + return codes; + } + [HarmonyPatch(typeof(NetPackageHoldingItem), nameof(NetPackageHoldingItem.ProcessPackage))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ProcessPackage_NetPackageHoldingItem(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var fld_entityid = AccessTools.Field(typeof(NetPackagePlayerStats), nameof(NetPackageHoldingItem.entityId)); + var fld_itemstack = AccessTools.Field(typeof(NetPackagePlayerStats), nameof(NetPackageHoldingItem.holdingItemStack)); + codes.InsertRange(codes.Count - 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, fld_entityid), + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldfld, fld_itemstack), + CodeInstruction.Call(typeof(MultiActionPatches), nameof(CheckItemValueMode)) + }); + + return codes; + } + + private static void CheckItemValueMode(int entityId, ItemStack holdingItemStack) + { + ItemValue itemValue = holdingItemStack.itemValue; + if (itemValue.HasMetadata(MultiActionMapping.STR_MULTI_ACTION_INDEX)) + { + int mode = (int)itemValue.GetMetadata(MultiActionMapping.STR_MULTI_ACTION_INDEX); + if (MultiActionManager.SetModeForEntity(entityId, mode) && ConnectionManager.Instance.IsServer) + { + ConnectionManager.Instance.SendPackage(NetPackageManager.GetPackage().Setup(entityId, mode), false, -1, entityId); + } + } + } + + [HarmonyPatch(typeof(GameManager), nameof(GameManager.UpdateTick))] + [HarmonyPostfix] + private static void Postfix_UpdateTick_GameManager(GameManager __instance) + { + if (MultiActionManager.LocalModeChanged && __instance.m_World != null) + { + MultiActionManager.LocalModeChanged = false; + int playerID = __instance.m_World.GetPrimaryPlayerId(); + if (ConnectionManager.Instance.IsClient) + { + ConnectionManager.Instance.SendToServer(NetPackageManager.GetPackage().Setup(playerID, MultiActionManager.GetModeForEntity(playerID))); + } + else + { + ConnectionManager.Instance.SendPackage(NetPackageManager.GetPackage().Setup(playerID, MultiActionManager.GetModeForEntity(playerID)), false, -1, playerID); + } + } + } + #endregion + + #region Input Handling + [HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))] + [HarmonyPrefix] + private static bool Prefix_Update_PlayerMoveController(PlayerMoveController __instance) + { + if (DroneManager.Debug_LocalControl || !__instance.gameManager.gameStateManager.IsGameStarted() || GameStats.GetInt(EnumGameStats.GameState) != 1) + return true; + + bool isUIOpen = __instance.windowManager.IsCursorWindowOpen() || __instance.windowManager.IsInputActive() || __instance.windowManager.IsModalWindowOpen(); + + MultiActionManager.UpdateLocalInput(__instance.entityPlayerLocal, __instance.playerInput, isUIOpen, Time.deltaTime); + + return true; + } + #endregion + + #region HUD display + /// + /// redirect check to alternative action module + /// + /// + /// + [HarmonyPatch(typeof(XUiC_HUDStatBar), nameof(XUiC_HUDStatBar.HasChanged))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_HasChanged_XUiC_HUDStatBar(IEnumerable instructions) + { + var codes = instructions.ToList(); + + MethodInfo mtd_edittool = AccessTools.Method(typeof(ItemAction), nameof(ItemAction.IsEditingTool)); + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.Calls(mtd_edittool)) + { + codes.RemoveRange(i - 1, 3); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(XUiC_HUDStatBar), nameof(XUiC_HUDStatBar.SetupActiveItemEntry))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SetupActiveItemEntry_XUiC_HUDStatBar(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + var lbd_index = generator.DeclareLocal(typeof(int)); + FieldInfo fld_action = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions)); + FieldInfo fld_ammoindex = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.SelectedAmmoTypeIndex)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_action)) + { + codes.RemoveAt(i + 1); + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldloc_2), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetActionIndexByMetaData)), + new CodeInstruction(OpCodes.Dup), + new CodeInstruction(OpCodes.Stloc_S, lbd_index) + }); + i += 3; + } + else if (codes[i].LoadsField(fld_ammoindex)) + { + codes[i].opcode = OpCodes.Call; + codes[i].operand = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetSelectedAmmoIndexByActionIndex)); + codes.Insert(i, new CodeInstruction(OpCodes.Ldloc_S, lbd_index)); + break; + } + } + return codes; + } + + [HarmonyPatch(typeof(XUiC_Radial), nameof(XUiC_Radial.handleActivatableItemCommand))] + [HarmonyPrefix] + private static bool Prefix_handleActivatableItemCommand_XUiC_Radial(XUiC_Radial _sender) + { + EntityPlayerLocal entityPlayer = _sender.xui.playerUI.entityPlayer; + MultiActionUtils.SetMinEventParamsByEntityInventory(entityPlayer); + return true; + } + + [HarmonyPatch(typeof(XUiC_ItemInfoWindow), nameof(XUiC_ItemInfoWindow.GetBindingValue))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_GetBindingValue_XUiC_ItemInfoWindow(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var fld_actions = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_actions) && codes[i + 1].opcode == OpCodes.Ldc_I4_0) + { + codes.RemoveAt(i + 1); + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(XUiC_ItemInfoWindow), nameof(XUiC_ItemInfoWindow.itemStack)), + CodeInstruction.LoadField(typeof(ItemStack), nameof(ItemStack.itemValue)), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetActionIndexByMetaData)) + }); + i += 3; + } + } + + return codes; + } + #endregion + + #region Cancel reload on switching item + //redirect these calls to action 0 and handle them in alternative module + //may change in the future + [HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_Update_PlayerMoveController(IEnumerable instructions) + { + var codes = instructions.ToList(); + + MethodInfo mtd_getgun = AccessTools.Method(typeof(Inventory), nameof(Inventory.GetHoldingGun)); + MethodInfo mtd_getprimary = AccessTools.Method(typeof(Inventory), nameof(Inventory.GetHoldingPrimary)); + FieldInfo fld_reload = AccessTools.Field(typeof(PlayerActionsPermanent), nameof(PlayerActionsPermanent.Reload)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_getgun)) + { + codes[i].operand = mtd_getprimary; + //codes.RemoveAt(i - 2); + //codes.InsertRange(i - 2, new[] + //{ + // new CodeInstruction(OpCodes.Ldarg_0), + // CodeInstruction.LoadField(typeof(PlayerMoveController), "entityPlayerLocal"), + // CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.GetActionIndexForEntity)) + //}); + //i += 2; + } + else if (codes[i].LoadsField(fld_reload)) + { + var label = codes[i + 6].operand; + codes.InsertRange(i + 7, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(PlayerMoveController), nameof(PlayerMoveController.entityPlayerLocal)), + CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.inventory)), + CodeInstruction.Call(typeof(Inventory), nameof(Inventory.GetIsFinishedSwitchingHeldItem)), + new CodeInstruction(OpCodes.Brfalse, label) + }); + i += 5; + } + } + + return codes; + } + #endregion + + #region Underwater check + //skip underwater check if action is not current action + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.OnHoldingUpdate))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_OnHoldingUpdate_ItemActionRanged(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var fld_ammonames = AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.MagazineItemNames)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_ammonames) && (codes[i + 1].opcode == OpCodes.Brfalse_S || codes[i + 1].opcode == OpCodes.Brfalse)) + { + var jumpto = codes[i + 1].operand; + codes.InsertRange(i - 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_1).WithLabels(codes[i - 1].ExtractLabels()), + CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.indexInEntityOfAction)), + new CodeInstruction(OpCodes.Ldarg_1), + CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)), + CodeInstruction.LoadField(typeof(ItemInventoryData), nameof(ItemInventoryData.holdingEntity)), + CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.GetActionIndexForEntity)), + new CodeInstruction(OpCodes.Bne_Un_S, jumpto) + }); + break; + } + } + + return codes; + } + #endregion + + #region GameEvent + [HarmonyPatch(typeof(ActionUnloadItems), nameof(ActionUnloadItems.HandleItemStackChange))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_HandleItemStackChange_ActionUnloadItems(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + var fld_actions = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.Actions)); + + for (var i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_actions)) + { + var label = generator.DefineLabel(); + codes[i - 1].WithLabels(label); + codes.InsertRange(i - 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Ldind_Ref), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ActionUnloadItems), nameof(ActionUnloadItems.ItemStacks)), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.MultiActionRemoveAmmoFromItemStack)), + new CodeInstruction(OpCodes.Brfalse_S, label), + new CodeInstruction(OpCodes.Ldc_I4_1), + new CodeInstruction(OpCodes.Ret) + }); + break; + } + } + + return codes; + } + #endregion + + #region fast toolbelt item switching issue fix + private static Coroutine switchHoldingItemCo; + [HarmonyPatch(typeof(Inventory), nameof(Inventory.ShowHeldItem))] + [HarmonyPrefix] + private static bool Prefix_ShowHeldItem_Inventory(bool show, Inventory __instance) + { + //Log.Out($"ShowHeldItem {show} on entity {__instance.entity.entityName}\n{StackTraceUtility.ExtractStackTrace()}"); + if (show && __instance.entity is EntityPlayerLocal && switchHoldingItemCo != null) + { + GameManager.Instance.StopCoroutine(switchHoldingItemCo); + switchHoldingItemCo = null; + __instance.SetIsFinishedSwitchingHeldItem(); + } + return true; + } + + [HarmonyPatch(typeof(Inventory), nameof(Inventory.ShowHeldItem))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ShowHeldItem_Inventory(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Pop) + { + var label = generator.DefineLabel(); + codes[i].WithLabels(label); + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Brfalse_S, label), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(Inventory), nameof(Inventory.entity)), + new CodeInstruction(OpCodes.Isinst, typeof(EntityPlayerLocal)), + new CodeInstruction(OpCodes.Brfalse_S, label), + CodeInstruction.StoreField(typeof(MultiActionPatches), nameof(switchHoldingItemCo)), + new CodeInstruction(OpCodes.Ret) + }); + break; + } + } + return codes; + } + #endregion + + #region item info display fix + [HarmonyPatch(typeof(XUiM_ItemStack), nameof(XUiM_ItemStack.GetStatItemValueTextWithModInfo))] + [HarmonyPrefix] + private static bool Prefix_GetStatItemValueTextWithModInfo_XUiM_ItemStack(ItemStack itemStack) + { + MultiActionUtils.SetCachedEventParamsDummyAction(itemStack); + return true; + } + + [HarmonyPatch(typeof(XUiM_ItemStack), nameof(XUiM_ItemStack.GetStatItemValueTextWithModColoring))] + [HarmonyPrefix] + private static bool Prefix_GetStatItemValueTextWithModColoring_XUiM_ItemStack(ItemStack itemStack) + { + MultiActionUtils.SetCachedEventParamsDummyAction(itemStack); + return true; + } + + [HarmonyPatch(typeof(XUiM_ItemStack), nameof(XUiM_ItemStack.GetStatItemValueTextWithCompareInfo))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_GetStatItemValueTextWithCompareInfo_XUiM_ItemStack(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue)); + var fld_seed = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.Seed)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_getvalue)) + { + codes.InsertRange(i + 2, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.SetCachedEventParamsDummyAction)), + }); + for (int j = i; j >= 0; j--) + { + if (codes[j].StoresField(fld_seed)) + { + codes.InsertRange(j + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.SetCachedEventParamsDummyAction)) + }); + codes.RemoveRange(j - 8, 9); + break; + } + } + break; + } + } + + return codes.Manipulator(static ins => ins.IsLdarg(2), static ins => ins.opcode = OpCodes.Ldnull); + } + + [HarmonyPatch(typeof(XUiC_ItemStack), nameof(XUiC_ItemStack.GetBindingValue))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_GetBindingValue_XUiC_ItemStack(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var prop_perc = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.PercentUsesLeft)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(prop_perc)) + { + codes.InsertRange(i - 3, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(XUiC_ItemStack), nameof(XUiC_ItemStack.itemStack)), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.SetCachedEventParamsDummyAction)) + }); + break; + } + } + + return codes; + } + #endregion + + #region ItemAction exclude tags + [HarmonyPatch(typeof(GameManager), nameof(GameManager.StartGame))] + [HarmonyPrefix] + private static bool Prefix_StartGame_GameManager() + { + MultiActionManager.PreloadCleanup(); + return true; + } + + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.LateInit))] + [HarmonyPostfix] + private static void Postfix_LateInit_ItemClass(ItemClass __instance) + { + MultiActionManager.ParseItemActionExcludeTagsAndModifiers(__instance); + } + + /// + /// + /// + /// + /// + [HarmonyPatch(typeof(EffectManager), nameof(EffectManager.GetValue))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_GetValue_EffectManager(IEnumerable instructions) + { + var codes = instructions.ToList(); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].IsStarg(5)) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_1).WithLabels(codes[i + 1].ExtractLabels()), + CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.CachedEventParam)), + CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.ItemActionData)), + new CodeInstruction(OpCodes.Ldarga_S, 5), + CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ModifyItemTags)) + }); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(EffectManager), nameof(EffectManager.GetValuesAndSources))] + [HarmonyPrefix] + private static bool Prefix_GetValuesAndSources_EffectManager(ItemValue _originalItemValue, EntityAlive _entity, ref FastTags tags) + { + MultiActionManager.ModifyItemTags(_originalItemValue, _entity?.MinEventContext?.ItemActionData, ref tags); + return true; + } + #endregion + + #region ItemAction exclude modifiers + //see Transpiler_ModifyValue_ItemValue + //see Transpiler_GetModifiedValueData_ItemValue + //see MultiActionProjectileRewrites.ProjectileValueModifyValue + //see MultiActionUtils.GetPropertyOverrideForAction + //see MultiActionManager.ParseItemActionExcludeTagsAndModifiers + #endregion + + #region requirement tags exclude + //[HarmonyPatch(typeof(TriggerHasTags), nameof(TriggerHasTags.IsValid))] + //[HarmonyTranspiler] + //private static IEnumerable Transpiler_IsValid_TriggerHasTags(IEnumerable instructions, ILGenerator generator) + //{ + // var codes = instructions.ToList(); + + // var lbd_tags = generator.DeclareLocal(typeof(FastTags)); + // FieldInfo fld_tags = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.Tags)); + // bool firstRet = true; + + // for (int i = 0; i < codes.Count; i++) + // { + // if (codes[i].opcode == OpCodes.Ret && firstRet) + // { + // firstRet = false; + // codes.InsertRange(i + 1, new[] + // { + // new CodeInstruction(OpCodes.Ldarg_1), + // new CodeInstruction(OpCodes.Ldfld, fld_tags), + // new CodeInstruction(OpCodes.Stloc_S, lbd_tags), + // new CodeInstruction(OpCodes.Ldarg_1), + // CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.ItemValue)), + // new CodeInstruction(OpCodes.Ldarg_1), + // CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.ItemActionData)), + // new CodeInstruction(OpCodes.Ldloca_S, lbd_tags), + // CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ModifyItemTags)) + // }); + // i += 9; + // } + // else if (codes[i].LoadsField(fld_tags)) + // { + // codes[i].opcode = OpCodes.Ldloca_S; + // codes[i].operand = lbd_tags; + // codes[i].WithLabels(codes[i - 1].ExtractLabels()); + // codes.RemoveAt(i - 1); + // i--; + // } + // } + + // return codes; + //} + + [HarmonyPatch(typeof(ItemHasTags), nameof(ItemHasTags.IsValid))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_IsValid_ItemHasTags(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + var lbd_tags = generator.DeclareLocal(typeof(FastTags)); + FieldInfo fld_itemvalue = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.ItemValue)); + FieldInfo fld_hasalltags = AccessTools.Field(typeof(ItemHasTags), nameof(ItemHasTags.hasAllTags)); + MethodInfo prop_itemclass = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.ItemClass)); + MethodInfo mtd_hasanytags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAnyTags)); + MethodInfo mtd_hasalltags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAllTags)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_hasalltags)) + { + codes.InsertRange(i - 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Ldfld, fld_itemvalue), + new CodeInstruction(OpCodes.Callvirt, prop_itemclass), + CodeInstruction.LoadField(typeof(ItemClass), nameof(ItemClass.ItemTags)), + new CodeInstruction(OpCodes.Stloc_S, lbd_tags), + new CodeInstruction(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Ldfld, fld_itemvalue), + new CodeInstruction(OpCodes.Ldarg_1), + CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.ItemActionData)), + new CodeInstruction(OpCodes.Ldloca_S, lbd_tags), + CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ModifyItemTags)) + }); + i += 11; + } + else if (codes[i].Calls(mtd_hasanytags)) + { + codes[i].opcode = OpCodes.Call; + codes[i].operand = AccessTools.Method(typeof(FastTags), nameof(FastTags.Test_AnySet)); + var labels = codes[i - 5].ExtractLabels(); + codes.RemoveRange(i - 5, 3); + codes.Insert(i - 5, new CodeInstruction(OpCodes.Ldloca_S, lbd_tags).WithLabels(labels)); + i -= 2; + } + else if (codes[i].Calls(mtd_hasalltags)) + { + codes[i].opcode = OpCodes.Call; + codes[i].operand = AccessTools.Method(typeof(FastTags), nameof(FastTags.Test_AllSet)); + var labels = codes[i - 5].ExtractLabels(); + codes.RemoveRange(i - 5, 3); + codes.Insert(i - 5, new CodeInstruction(OpCodes.Ldloca_S, lbd_tags).WithLabels(labels)); + i -= 2; + } + } + return codes; + } + + + [HarmonyPatch(typeof(HoldingItemHasTags), nameof(ItemHasTags.IsValid))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_IsValid_HoldingItemHasTags(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + var lbd_tags = generator.DeclareLocal(typeof(FastTags)); + FieldInfo fld_itemvalue = AccessTools.Field(typeof(MinEventParams), nameof(MinEventParams.ItemValue)); + FieldInfo fld_hasalltags = AccessTools.Field(typeof(HoldingItemHasTags), nameof(HoldingItemHasTags.hasAllTags)); + MethodInfo prop_itemclass = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.ItemClass)); + MethodInfo prop_itemvalue = AccessTools.PropertyGetter(typeof(Inventory), nameof(Inventory.holdingItemItemValue)); + MethodInfo mtd_hasanytags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAnyTags)); + MethodInfo mtd_hasalltags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAllTags)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_hasalltags)) + { + codes.InsertRange(i - 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(HoldingItemHasTags), nameof(HoldingItemHasTags.target)), + CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.inventory)), + new CodeInstruction(OpCodes.Callvirt, prop_itemvalue), + new CodeInstruction(OpCodes.Callvirt, prop_itemclass), + CodeInstruction.LoadField(typeof(ItemClass), nameof(ItemClass.ItemTags)), + new CodeInstruction(OpCodes.Stloc_S, lbd_tags), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(HoldingItemHasTags), nameof(HoldingItemHasTags.target)), + CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.inventory)), + new CodeInstruction(OpCodes.Callvirt, prop_itemvalue), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(HoldingItemHasTags), nameof(HoldingItemHasTags.target)), + CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)), + CodeInstruction.LoadField(typeof(MinEventParams), nameof(MinEventParams.ItemActionData)), + new CodeInstruction(OpCodes.Ldloca_S, lbd_tags), + CodeInstruction.Call(typeof(MultiActionManager), nameof(MultiActionManager.ModifyItemTags)) + }); + i += 17; + } + else if (codes[i].Calls(mtd_hasanytags)) + { + codes[i].opcode = OpCodes.Call; + codes[i].operand = AccessTools.Method(typeof(FastTags), nameof(FastTags.Test_AnySet)); + var labels = codes[i - 6].ExtractLabels(); + codes.RemoveRange(i - 6, 4); + codes.Insert(i - 6, new CodeInstruction(OpCodes.Ldloca_S, lbd_tags).WithLabels(labels)); + i -= 3; + } + else if (codes[i].Calls(mtd_hasalltags)) + { + codes[i].opcode = OpCodes.Call; + codes[i].operand = AccessTools.Method(typeof(FastTags), nameof(FastTags.Test_AllSet)); + var labels = codes[i - 6].ExtractLabels(); + codes.RemoveRange(i - 6, 4); + codes.Insert(i - 6, new CodeInstruction(OpCodes.Ldloca_S, lbd_tags).WithLabels(labels)); + i -= 3; + } + } + return codes; + } + #endregion + + #region Inventory make ItemValue valid on creating inventory data + [HarmonyPatch(typeof(Inventory), nameof(Inventory.SetItem), new[] { typeof(int), typeof(ItemValue), typeof(int), typeof(bool) })] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SetItem_Inventory(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_clone = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.Clone)); + var mtd_create = AccessTools.Method(typeof(Inventory), nameof(Inventory.createHeldItem)); + var mtd_invdata = AccessTools.Method(typeof(Inventory), nameof(Inventory.createInventoryData)); + for (int i = 0; i < codes.Count; i++) + { + //if (codes[i].opcode == OpCodes.Ldarg_3 && (codes[i + 1].opcode == OpCodes.Brtrue_S || codes[i + 1].opcode == OpCodes.Brtrue)) + //{ + // var label = codes[i + 4].ExtractLabels(); + // codes.InsertRange(i + 4, new[] + // { + // new CodeInstruction(OpCodes.Ldarg_2).WithLabels(label), + // new CodeInstruction(OpCodes.Callvirt, mtd_clone), + // new CodeInstruction(OpCodes.Starg_S, 2) + // }); + // i += 7; + //} + //else + if (codes[i].Calls(mtd_create)) + { + codes.InsertRange(i - 12, new[] + { + new CodeInstruction(OpCodes.Ldarg_2), + CodeInstruction.StoreField(typeof(ActionModuleAlternative), nameof(ActionModuleAlternative.InventorySetItemTemp)) + }); + i += 4; + for (int j = i; j < codes.Count; j++) + { + if (codes[j].Calls(mtd_invdata)) + { + codes.InsertRange(j + 2, new[] + { + new CodeInstruction(OpCodes.Ldnull), + CodeInstruction.StoreField(typeof(ActionModuleAlternative), nameof(ActionModuleAlternative.InventorySetItemTemp)) + }); + i = j + 4; + break; + } + } + break; + } + //else if (codes[i].Calls(mtd_clone)) + //{ + // codes.RemoveAt(i); + // break; + //} + } + + return codes; + } + + [HarmonyPatch(typeof(Inventory), nameof(Inventory.ForceHoldingItemUpdate))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ForceHoldingItemUpdate_Inventory(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_invdata = AccessTools.Method(typeof(Inventory), nameof(Inventory.createInventoryData)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_invdata)) + { + codes.InsertRange(i + 2, new[] + { + new CodeInstruction(OpCodes.Ldnull), + CodeInstruction.StoreField(typeof(ActionModuleAlternative), nameof(ActionModuleAlternative.InventorySetItemTemp)) + }); + codes.InsertRange(i - 8, new[] + { + new CodeInstruction(OpCodes.Ldloc_0).WithLabels(codes[i - 8].ExtractLabels()), + CodeInstruction.StoreField(typeof(ActionModuleAlternative), nameof(ActionModuleAlternative.InventorySetItemTemp)) + }); + break; + } + } + + return codes; + } + #endregion + + #region Temporaty fix for hud ammo mismatch + [HarmonyPatch(typeof(XUiC_HUDStatBar), nameof(XUiC_HUDStatBar.Update))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_Update_XUiC_HUDStatBar(IEnumerable instructions) + { + MethodInfo mtd_getfocus = AccessTools.Method(typeof(Inventory), nameof(Inventory.GetFocusedItemIdx)); + MethodInfo mtd_getholding = AccessTools.PropertyGetter(typeof(Inventory), nameof(Inventory.holdingItemIdx)); + + foreach (var ins in instructions) + { + if (ins.Calls(mtd_getfocus)) + { + ins.operand = mtd_getholding; + } + yield return ins; + } + } + #endregion + } + + //Moved to MultiActionFix + //#region Ranged Reload + //[HarmonyPatch] + //public static class RangedReloadPatches + //{ + // private static IEnumerable TargetMethods() + // { + // return new MethodInfo[] + // { + // AccessTools.Method(typeof(ItemActionAttack), nameof(ItemActionAttack.ReloadGun)), + // AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.ReloadGun)), + // AccessTools.Method(typeof(ItemActionLauncher), nameof(ItemActionLauncher.ReloadGun)) + // }; + // } + + // //Why? Ask TFP why they don't just call base.ReloadGun() + // [HarmonyPrefix] + // private static bool Prefix_ReloadGun(ItemActionData _actionData) + // { + // int reloadAnimationIndex = MultiActionManager.GetMetaIndexForActionIndex(_actionData.invData.holdingEntity.entityId, _actionData.indexInEntityOfAction); + // _actionData.invData.holdingEntity.emodel?.avatarController?.UpdateInt(AvatarController.itemActionIndexHash, reloadAnimationIndex, false); + // _actionData.invData.holdingEntity.MinEventContext.ItemActionData = _actionData; + // return true; + // } + //} + //#endregion + + //KEEP + #region Melee action tags + [HarmonyPatch] + public static class ActionTagPatches1 + { + private static IEnumerable TargetMethods() + { + return new MethodInfo[] + { + AccessTools.Method(typeof(AnimatorMeleeAttackState), nameof(AnimatorMeleeAttackState.OnStateEnter), new[] {typeof(Animator), typeof(AnimatorStateInfo), typeof(int)}), + AccessTools.Method(typeof(ItemActionAttack), nameof(ItemActionAttack.GetDamageBlock)), + AccessTools.Method(typeof(ItemActionAttack), nameof(ItemActionAttack.GetDamageEntity)), + AccessTools.Method(typeof(ItemActionDynamic), nameof(ItemActionDynamic.GetDamageBlock)), + AccessTools.Method(typeof(ItemActionDynamic), nameof(ItemActionDynamic.GetDamageEntity)), + AccessTools.Method(typeof(ItemActionThrownWeapon), nameof(ItemActionThrownWeapon.GetDamageBlock)), + AccessTools.Method(typeof(ItemActionThrownWeapon), nameof(ItemActionThrownWeapon.GetDamageEntity)) + }; + } + + //set correct tag for action index above 2 + //only action 1 uses secondary tag, others still use primary + [HarmonyTranspiler] + private static IEnumerable Transpiler(IEnumerable instructions) + { + var codes = instructions.ToList(); + + FieldInfo fld_tag = AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.SecondaryTag)); + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.LoadsField(fld_tag)) + { + codes.InsertRange(i - 1, new[] + { + new CodeInstruction(OpCodes.Ldc_I4_1), + new CodeInstruction(OpCodes.Ceq) + }); + i += 2; + } + } + + return codes; + } + } + + [HarmonyPatch] + public static class ActionTagPatches2 + { + private static IEnumerable TargetMethods() + { + return new MethodInfo[] + { + AccessTools.Method(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.Raycast)), + AccessTools.Method(typeof(ItemActionDynamic), nameof(ItemActionDynamic.GetExecuteActionGrazeTarget)), + AccessTools.Method(typeof(ItemActionDynamic), nameof(ItemActionDynamic.hitTarget)), + AccessTools.Method(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.canStartAttack)), + AccessTools.Method(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.OnHoldingUpdate)), + AccessTools.Method(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.SetAttackFinished)), + AccessTools.Method(typeof(ItemActionMelee), nameof(ItemActionMelee.OnHoldingUpdate)), + AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.ExecuteAction)), + AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.fireShot)), + AccessTools.Method(typeof(ItemActionThrownWeapon), nameof(ItemActionThrownWeapon.throwAway)), + AccessTools.Method(typeof(ItemActionUseOther), nameof(ItemActionUseOther.ExecuteAction)), + + }; + } + + [HarmonyTranspiler] + private static IEnumerable Transpiler(IEnumerable instructions) + { + var codes = instructions.ToList(); + + FieldInfo fld_index = AccessTools.Field(typeof(ItemActionData), nameof(ItemActionData.indexInEntityOfAction)); + for (int i = 0; i < codes.Count - 1; i++) + { + var code = codes[i]; + if (code.LoadsField(fld_index) && (codes[i + 1].opcode == OpCodes.Brfalse_S || codes[i + 1].opcode == OpCodes.Brfalse)) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldc_I4_1), + new CodeInstruction(OpCodes.Ceq) + }); + i += 2; + } + } + + return codes; + } + } + #endregion + + //KEEP + #region 3 + [HarmonyPatch] + public static class ThreePatches + { + private static IEnumerable TargetMethods() + { + return new MethodInfo[] + { + AccessTools.Method(typeof(ItemClass), nameof(ItemClass.OnHoldingUpdate)), + AccessTools.Method(typeof(ItemClass), nameof(ItemClass.CleanupHoldingActions)), + AccessTools.Method(typeof(ItemClass), nameof(ItemClass.StartHolding)), + AccessTools.Method(typeof(ItemClass), nameof(ItemClass.StopHolding)), + AccessTools.Method(typeof(ItemClass), nameof(ItemClass.IsActionRunning)) + }; + } + + [HarmonyTranspiler] + private static IEnumerable Transpiler_Three(IEnumerable instructions) + { + foreach (var instruction in instructions) + { + if (instruction.opcode == OpCodes.Ldc_I4_3) + instruction.opcode = OpCodes.Ldc_I4_5; + yield return instruction; + } + } + } + #endregion + + #region ItemAction property override + [HarmonyPatch] + public static class ItemActionPropertyOverridePatches + { + private static IEnumerable TargetMethods() + { + return AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(a => + { + try + { + return a.GetTypes(); + } + catch + { + return new Type[0]; + } + }) + .Where(t => t.IsSubclassOf(typeof(ItemAction))) + .Select(t => AccessTools.Method(t, nameof(ItemAction.OnModificationsChanged))) + .Where(m => m.IsDeclaredMember()); + } + + [HarmonyTranspiler] + private static IEnumerable Transpiler(IEnumerable instructions, MethodBase __originalMethod) + { + Log.Out($"Patching property override method {__originalMethod.DeclaringType.Name}.{__originalMethod.Name}"); + var codes = instructions.ToList(); + var mtd_override = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.GetPropertyOverride)); + var mtd_newoverride = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetPropertyOverrideForAction)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_override)) + { + codes[i].opcode = OpCodes.Call; + codes[i].operand = mtd_newoverride; + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.ActionIndex)) + }); + i += 2; + } + } + return codes; + } + } + + #endregion + + #region Remove ammo + [HarmonyPatch] + public static class RemoveAmmoPatches + { + private static IEnumerable TargetMethods() + { + return new[] + { + AccessTools.Method(typeof(ItemActionEntryAssemble), nameof(ItemActionEntryAssemble.HandleRemoveAmmo)), + AccessTools.Method(typeof(ItemActionEntryScrap), nameof(ItemActionEntryScrap.HandleRemoveAmmo)), + AccessTools.Method(typeof(ItemActionEntrySell), nameof(ItemActionEntrySell.HandleRemoveAmmo)), + }; + } + + [HarmonyPrefix] + private static bool Prefix(BaseItemActionEntry __instance, ItemStack stack, ref ItemStack __result) + { + List list_ammo_stack = new List(); + if (!MultiActionUtils.MultiActionRemoveAmmoFromItemStack(stack, list_ammo_stack)) + return true; + + foreach (var ammoStack in list_ammo_stack) + { + if (!__instance.ItemController.xui.PlayerInventory.AddItem(ammoStack)) + { + __instance.ItemController.xui.PlayerInventory.DropItem(ammoStack); + } + } + __result = stack; + return false; + } + } + #endregion + + #region Generate initial meta + [HarmonyPatch] + public static class InitialMetaPatches + { + private static IEnumerable TargetMethods() + { + return new MethodInfo[] + { + AccessTools.Method(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.SetupStartingItems)), + AccessTools.Method(typeof(ItemClass), nameof(ItemClass.CreateItemStacks)) + }; + } + + [HarmonyTranspiler] + private static IEnumerable Transpiler(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_initial = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.GetInitialMetadata)); + var mtd_initialnew = AccessTools.Method(typeof(MultiActionUtils), nameof(MultiActionUtils.GetMultiActionInitialMetaData)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_initial)) + { + codes[i].opcode = OpCodes.Call; + codes[i].operand = mtd_initialnew; + break; + } + } + + return codes; + } + } + #endregion + + #region Item Info DisplayType + [HarmonyPatch] + public static class DisplayTypePatches + { + [HarmonyPatch(typeof(XUiC_AssembleWindow), nameof(XUiC_AssembleWindow.ItemStack), MethodType.Setter)] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ItemStack_XUiC_AssembleWindow(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var fld_displaytype = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.DisplayType)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_displaytype)) + { + codes.RemoveRange(i - 1, 2); + codes.InsertRange(i - 1, new[] + { + CodeInstruction.LoadField(typeof(XUiC_AssembleWindow), nameof(XUiC_AssembleWindow.itemStack)), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetDisplayTypeForAction), new []{ typeof(ItemStack) }) + }); + break; + } + } + return codes; + } + + [HarmonyPatch(typeof(XUiC_ItemInfoWindow), nameof(XUiC_ItemInfoWindow.SetInfo))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SetInfo_XUiC_ItemInfoWindow(IEnumerable instructions, MethodBase originalMethod) + { + var codes = instructions.ToList(); + + var fld_displaytype = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.DisplayType)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_displaytype)) + { + codes.RemoveRange(i - 1, 2); + codes.InsertRange(i - 1, new[] + { + CodeInstruction.LoadField(typeof(XUiC_ItemInfoWindow), nameof(XUiC_ItemInfoWindow.itemStack)), + CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetDisplayTypeForAction), new []{ typeof(ItemStack) }) + }); + break; + } + } + return codes; + } + + [HarmonyPatch(typeof(XUiM_ItemStack), nameof(XUiM_ItemStack.HasItemStats))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_HasItemStats_XUiM_ItemStack(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var fld_displaytype = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.DisplayType)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_displaytype)) + { + codes.RemoveRange(i - 1, 2); + codes.Insert(i - 1, CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.GetDisplayTypeForAction), new []{ typeof(ItemValue) })); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(XUiC_ItemInfoWindow), nameof(XUiC_ItemInfoWindow.HoverEntry), MethodType.Setter)] + [HarmonyTranspiler] + private static IEnumerable Transpiler_HoverEntry_XUiC_ItemInfoWindow(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_cancompare = AccessTools.Method(typeof(XUiM_ItemStack), nameof(XUiM_ItemStack.CanCompare)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_cancompare)) + { + codes[i] = CodeInstruction.Call(typeof(MultiActionUtils), nameof(MultiActionUtils.CanCompare)); + codes[i - 1] = CodeInstruction.LoadField(typeof(XUiC_ItemInfoWindow), nameof(XUiC_ItemInfoWindow.itemStack)); + codes.Insert(i, CodeInstruction.LoadField(typeof(ItemStack), nameof(ItemStack.itemValue))); + codes.RemoveAt(i - 3); + break; + } + } + return codes; + } + } + #endregion +} diff --git a/Harmony/MultiActionReversePatches.cs b/Harmony/MultiActionReversePatches.cs new file mode 100644 index 0000000..622ec55 --- /dev/null +++ b/Harmony/MultiActionReversePatches.cs @@ -0,0 +1,68 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Utilities; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using UnityEngine; + +[HarmonyPatch] +public static class MultiActionReversePatches +{ + [HarmonyReversePatch(HarmonyReversePatchType.Snapshot)] + [HarmonyPatch(typeof(EffectManager), nameof(EffectManager.GetValue))] + public static float ProjectileGetValue(PassiveEffects _passiveEffect, ItemValue _originalItemValue = null, float _originalValue = 0f, EntityAlive _entity = null, Recipe _recipe = null, FastTags tags = default(FastTags), bool calcEquipment = true, bool calcHoldingItem = true, bool calcProgression = true, bool calcBuffs = true, bool calcChallenges = true, int craftingTier = 1, bool useMods = true, bool _useDurability = false) + { + IEnumerable Transpiler(IEnumerable instructions) + { + if (instructions == null) + return null; + var codes = instructions.ToList(); + + var mtd_modify = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.ModifyValue)); + for (int i = 0; i < codes.Count; i++) + { + var code = codes[i]; + if (code.Calls(mtd_modify) && codes[i - 9].opcode == OpCodes.Ldarg_1) + { + code.operand = AccessTools.Method(typeof(MultiActionProjectileRewrites), nameof(MultiActionProjectileRewrites.ProjectileValueModifyValue)); + } + } + return codes; + } + + _ = Transpiler(null); + return _originalValue; + } + + [HarmonyReversePatch] + [HarmonyPatch(typeof(ProjectileMoveScript), nameof(ProjectileMoveScript.Fire))] + public static void ProjectileFire(this ProjectileMoveScript __instance, Vector3 _idealStartPosition, Vector3 _flyDirection, Entity _firingEntity, int _hmOverride = 0, float _radius = 0f) + { + IEnumerable Transpiler(IEnumerable instructions) + { + if (instructions == null) + return null; + + var codes = instructions.ToList(); + + FieldInfo fld_launcher = AccessTools.Field(typeof(ProjectileMoveScript), nameof(ProjectileMoveScript.itemValueLauncher)); + FieldInfo fld_projectile = AccessTools.Field(typeof(ProjectileMoveScript), nameof(ProjectileMoveScript.itemValueProjectile)); + MethodInfo mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue)); + MethodInfo mtd_getvaluenew = AccessTools.Method(typeof(MultiActionReversePatches), nameof(ProjectileGetValue)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_launcher)) + { + codes[i].operand = fld_projectile; + } + else if (codes[i].Calls(mtd_getvalue)) + { + codes[i].operand = mtd_getvaluenew; + } + } + return codes; + } + _ = Transpiler(null); + } +} \ No newline at end of file diff --git a/Harmony/MultiBarrelPatches.cs b/Harmony/MultiBarrelPatches.cs new file mode 100644 index 0000000..792e517 --- /dev/null +++ b/Harmony/MultiBarrelPatches.cs @@ -0,0 +1,155 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; +using System.Text; +using System.Threading.Tasks; + +namespace KFCommonUtilityLib.Harmony +{ + [HarmonyPatch] + public class MultiBarrelPatches + { + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ExecuteAction))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ExecuteAction_ItemActionRanged(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + var mtd_getmax = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.GetMaxAmmoCount)); + var mtd_consume = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.ConsumeAmmo)); + + Label loopStart = generator.DefineLabel(); + Label loopCondi = generator.DefineLabel(); + LocalBuilder lbd_data_module = generator.DeclareLocal(typeof(ActionModuleMultiBarrel.MultiBarrelData)); + LocalBuilder lbd_ismb = generator.DeclareLocal(typeof(bool)); + LocalBuilder lbd_i = generator.DeclareLocal(typeof(int)); + LocalBuilder lbd_rounds = generator.DeclareLocal(typeof(int)); + for (int i = 0; i < codes.Count; i++) + { + //prepare loop and store local variables + if (codes[i].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 6) + { + codes[i + 1].WithLabels(loopStart); + Label lbl = generator.DefineLabel(); + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldnull), + new CodeInstruction(OpCodes.Stloc_S, lbd_data_module), + new CodeInstruction(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Ldloca_S, lbd_data_module), + CodeInstruction.Call(typeof(MultiBarrelPatches), nameof(IsMultiBarrelData)), + new CodeInstruction(OpCodes.Stloc_S, lbd_ismb), + new CodeInstruction(OpCodes.Ldc_I4_0), + new CodeInstruction(OpCodes.Stloc_S, lbd_i), + new CodeInstruction(OpCodes.Ldloc_S, lbd_ismb), + new CodeInstruction(OpCodes.Brfalse_S, lbl), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.roundsPerShot)), + new CodeInstruction(OpCodes.Stloc_S, lbd_rounds), + new CodeInstruction(OpCodes.Br_S, loopCondi), + new CodeInstruction(OpCodes.Ldc_I4_1).WithLabels(lbl), + new CodeInstruction(OpCodes.Stloc_S, lbd_rounds), + new CodeInstruction(OpCodes.Br_S, loopCondi), + }); + i += 16; + } + //one round multi shot check + else if (codes[i].Calls(mtd_consume)) + { + Label lbl = generator.DefineLabel(); + codes[i - 2].WithLabels(lbl); + codes.InsertRange(i - 2, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_ismb), + new CodeInstruction(OpCodes.Brfalse_S, lbl), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.oneRoundMultishot)), + new CodeInstruction(OpCodes.Brfalse_S, lbl), + new CodeInstruction(OpCodes.Ldloc_S, lbd_i), + new CodeInstruction(OpCodes.Ldc_I4_0), + new CodeInstruction(OpCodes.Bgt_S, codes[i - 3].operand) + }); + i += 8; + } + //loop conditions and cycle barrels + else if (codes[i].Calls(mtd_getmax)) + { + Label lbl_pre = generator.DefineLabel(); + Label lbl_post = generator.DefineLabel(); + CodeInstruction origin = codes[i - 2]; + codes.InsertRange(i - 2, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_ismb).WithLabels(origin.ExtractLabels()), + new CodeInstruction(OpCodes.Brfalse_S, lbl_pre), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.muzzleIsPerRound)), + new CodeInstruction(OpCodes.Brfalse_S, lbl_pre), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.Call(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.CycleBarrels)), + new CodeInstruction(OpCodes.Ldloc_S, lbd_i).WithLabels(lbl_pre), + //new CodeInstruction(OpCodes.Dup), + //new CodeInstruction(OpCodes.Ldloc_S, lbd_rounds), + //CodeInstruction.Call(typeof(MultiBarrelPatches), nameof(MultiBarrelPatches.LogInfo)), + new CodeInstruction(OpCodes.Ldc_I4_1), + new CodeInstruction(OpCodes.Add), + new CodeInstruction(OpCodes.Stloc_S, lbd_i), + new CodeInstruction(OpCodes.Ldloc_S, lbd_i).WithLabels(loopCondi), + new CodeInstruction(OpCodes.Ldloc_S, lbd_rounds), + new CodeInstruction(OpCodes.Blt_S, loopStart), + new CodeInstruction(OpCodes.Ldloc_S, lbd_ismb), + new CodeInstruction(OpCodes.Brfalse_S, lbl_post), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.muzzleIsPerRound)), + new CodeInstruction(OpCodes.Brtrue_S, lbl_post), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.Call(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.CycleBarrels)) + }); + origin.WithLabels(lbl_post); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateEnter))] + [HarmonyPostfix] + private static void Postfix_OnStateEnter_AnimatorRangedReloadState(AnimatorRangedReloadState __instance) + { + ItemActionLauncher.ItemActionDataLauncher launcherData = __instance.actionData as ItemActionLauncher.ItemActionDataLauncher; + if (launcherData != null && launcherData is IModuleContainerFor dataModule && dataModule.Instance.oneRoundMultishot && dataModule.Instance.roundsPerShot > 1) + { + int count = launcherData.projectileInstance.Count; + int times = dataModule.Instance.roundsPerShot - 1; + for (int i = 0; i < count; i++) + { + for (int j = 0; j < times; j++) + { + launcherData.projectileJoint = dataModule.Instance.projectileJoints[j + 1]; + launcherData.projectileInstance.Insert(i * (times + 1) + j + 1,((ItemActionLauncher)__instance.actionRanged).instantiateProjectile(launcherData)); + } + } + } + } + + [HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateExit))] + [HarmonyPostfix] + private static void Postfix_OnStateExit_AnimatorRangedReloadState(AnimatorRangedReloadState __instance) + { + if (__instance.actionData is IModuleContainerFor dataModule) + { + dataModule.Instance.SetCurrentBarrel(__instance.actionData.invData.itemValue.Meta); + } + } + + private static bool IsMultiBarrelData(ItemActionData data, out ActionModuleMultiBarrel.MultiBarrelData dataModule) + { + return (dataModule = (data as IModuleContainerFor)?.Instance) != null; + } + + private static void LogInfo(int cur, int max) => Log.Out($"max rounds {max}, cur {cur}"); + } +} diff --git a/Harmony/Patches.cs b/Harmony/Patches.cs new file mode 100644 index 0000000..04f086d --- /dev/null +++ b/Harmony/Patches.cs @@ -0,0 +1,1325 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; +using System; +using System.Collections.Generic; +using UniLinq; +using System.Reflection; +using System.Reflection.Emit; +using System.Xml.Linq; +using UnityEngine; +using KFCommonUtilityLib.Scripts.NetPackages; +using KFCommonUtilityLib; + +[HarmonyPatch] +public static class CommonUtilityPatch +{ + //fix reloading issue and onSelfRangedBurstShot timing + public static void FakeReload(EntityAlive holdingEntity, ItemActionRanged.ItemActionDataRanged _actionData) + { + if (!holdingEntity) + return; + _actionData.isReloading = true; + _actionData.isWeaponReloading = true; + holdingEntity.MinEventContext.ItemActionData = _actionData; + holdingEntity.FireEvent(MinEventTypes.onReloadStart, true); + _actionData.isReloading = false; + _actionData.isWeaponReloading = false; + _actionData.isReloadCancelled = false; + _actionData.isWeaponReloadCancelled = false; + holdingEntity.FireEvent(MinEventTypes.onReloadStop); + + AnimationAmmoUpdateState.SetAmmoCountForEntity(holdingEntity, holdingEntity.inventory.holdingItemIdx); + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.SwapAmmoType))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SwapAmmoType_ItemActionRanged(IEnumerable instructions) + { + var codes = new List(instructions); + + for (int i = 0; i < codes.Count; ++i) + { + if (codes[i].opcode == OpCodes.Ret) + { + codes.InsertRange(i, new CodeInstruction[] + { + new CodeInstruction(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(FakeReload)) + }); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ExecuteAction))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ExecuteAction_ItemActionRanged(IEnumerable instructions) + { + var codes = new List(instructions); + var mtd_fire_event = AccessTools.Method(typeof(EntityAlive), nameof(EntityAlive.FireEvent)); + var mtd_get_model_layer = AccessTools.Method(typeof(EntityAlive), nameof(EntityAlive.GetModelLayer)); + var mtd_get_perc_left = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.PercentUsesLeft)); + + int take = -1, insert = -1; + for (int i = 0; i < codes.Count; ++i) + { + if (codes[i].opcode == OpCodes.Ldc_I4_S && codes[i].OperandIs((int)MinEventTypes.onSelfRangedBurstShotEnd) && codes[i + 2].Calls(mtd_fire_event)) + take = i - 3; + else if (codes[i].Calls(mtd_get_model_layer)) + insert = i + 2; + } + + if (take < insert) + { + var list = codes.GetRange(take, 6); + codes.InsertRange(insert, list); + codes.RemoveRange(take, 6); + } + + return codes; + } + //fix recoil animation does not match weapon RPM + private static int weaponFireHash = Animator.StringToHash("WeaponFire"); + private static int aimHash = Animator.StringToHash("IsAiming"); + private static HashSet hash_shot_state = new HashSet(); + private static HashSet hash_aimshot_state = new HashSet(); + + public static void InitShotStates() + { + string[] weapons = + { + "fpvAK47", + "fpvMagnum", + "fpvRocketLauncher", + "fpvSawedOffShotgun", + "fpvBlunderbuss", + "fpvCrossbow", + "fpvPistol", + "fpvHuntingRifle", + "fpvSMG", + "fpvSniperRifle", + "M60", + "fpvDoubleBarrelShotgun", + //"fpvJunkTurret", + "fpvTacticalAssaultRifle", + "fpvDesertEagle", + "fpvAutoShotgun", + "fpvSharpShooterRifle", + "fpvPipeMachineGun", + "fpvPipeRifle", + "fpvPipeRevolver", + "fpvPipeShotgun", + "fpvLeverActionRifle", + }; + foreach (string weapon in weapons) + { + hash_shot_state.Add(Animator.StringToHash(weapon + "Fire")); + hash_aimshot_state.Add(Animator.StringToHash(weapon + "AimFire")); + } + } + + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.OnFired))] + [HarmonyPostfix] + private static void Postfix_OnFired_EntityPlayerLocal(EntityPlayerLocal __instance) + { + if (!__instance.bFirstPersonView) + return; + + ItemActionRanged.ItemActionDataRanged _rangedData; + if ((_rangedData = __instance.inventory.holdingItemData.actionData[0] as ItemActionRanged.ItemActionDataRanged) == null && (_rangedData = __instance.inventory.holdingItemData.actionData[1] as ItemActionRanged.ItemActionDataRanged) == null) + return; + + if (_rangedData.invData.model.TryGetComponent(out var targets) && targets.ItemFpv) + return; + + var anim = (__instance.emodel.avatarController as AvatarLocalPlayerController).FPSArms.Animator; + if (anim.IsInTransition(0)) + return; + + var curState = anim.GetCurrentAnimatorStateInfo(0); + if (curState.length > _rangedData.Delay) + { + bool aimState = anim.GetBool(aimHash); + short shotState = 0; + if (hash_shot_state.Contains(curState.shortNameHash)) + shotState = 1; + else if (hash_aimshot_state.Contains(curState.shortNameHash)) + shotState = 2; + if (shotState == 0 || (shotState == 1 && aimState) || (shotState == 2 && !aimState)) + { + if (shotState > 0) + anim.ResetTrigger(weaponFireHash); + return; + } + + //current state, layer 0, offset 0 + anim.PlayInFixedTime(0, 0, 0); + anim.ResetTrigger(weaponFireHash); + if (_rangedData.invData.itemValue.Meta == 0) + { + __instance.emodel.avatarController.CancelEvent(weaponFireHash); + Log.Out("Cancel fire event because meta is 0"); + } + } + } + + //[HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ItemActionEffects))] + //[HarmonyPostfix] + //private static void Postfix_ItemActionEffects_ItemActionRanged(ItemActionData _actionData, int _firingState) + //{ + // if (_firingState == 0 && _actionData.invData.holdingEntity is EntityPlayerLocal && !(_actionData.invData.itemValue.ItemClass.Actions[0] is ItemActionCatapult)) + // { + // _actionData.invData.holdingEntity?.emodel.avatarController.CancelEvent(weaponFireHash); + // //Log.Out("Cancel fire event because firing state is 0\n" + StackTraceUtility.ExtractStackTrace()); + // } + //} + + //[HarmonyPatch(typeof(GameManager), "gmUpdate")] + //[HarmonyTranspiler] + //private static IEnumerable Transpiler_gmUpdate_GameManager(IEnumerable instructions) + //{ + // var codes = new List(instructions); + // var mtd_unload = AccessTools.Method(typeof(Resources), nameof(Resources.UnloadUnusedAssets)); + // var fld_duration = AccessTools.Field(typeof(GameManager), "unloadAssetsDuration"); + + // for (int i = 0; i < codes.Count; ++i) + // { + // if (codes[i].opcode == OpCodes.Call && codes[i].Calls(mtd_unload)) + // { + // for (int j = i; j >= 0; --j) + // { + // if (codes[j].opcode == OpCodes.Ldfld && codes[j].LoadsField(fld_duration) && codes[j + 1].opcode == OpCodes.Ldc_R4) + // codes[j + 1].operand = (float)codes[j + 1].operand / 2; + // } + // break; + // } + // } + + // return codes; + //} + + //internal static void ForceUpdateGC() + //{ + // if (GameManager.IsDedicatedServer) + // return; + // if (GameManager.frameCount % 18000 == 0) + // { + // long rss = GetRSS.GetCurrentRSS(); + // if (rss / 1024 / 1024 > 6144) + // { + // Log.Out("Memory usage exceeds threshold, now performing garbage collection..."); + // GC.Collect(); + // } + // } + //} + + //altmode workarounds + //deprecated by action module + private static void ParseAltRequirements(XElement _node) + { + string itemName = _node.GetAttribute("name"); + if (string.IsNullOrEmpty(itemName)) + { + return; + } + ItemClass item = ItemClass.GetItemClass(itemName); + for (int i = 0; i < item.Actions.Length; i++) + { + if (item.Actions[i] is ItemActionAltMode _alt) + _alt.ParseAltRequirements(_node, i); + } + } + + [HarmonyPatch(typeof(ItemClassesFromXml), nameof(ItemClassesFromXml.parseItem))] + [HarmonyPostfix] + private static void Postfix_parseItem_ItemClassesFromXml(XElement _node) + { + ParseAltRequirements(_node); + } + + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.ExecuteAction))] + [HarmonyPrefix] + private static bool Prefix_ExecuteAction_ItemClass(ItemClass __instance, int _actionIdx, ItemInventoryData _data, bool _bReleased) + { + if (!_bReleased && __instance.Actions[_actionIdx] is ItemActionAltMode _alt) + _alt.SetAltRequirement(_data.actionData[_actionIdx]); + + return true; + } + + [HarmonyPatch(typeof(DynamicProperties), nameof(DynamicProperties.Parse))] + [HarmonyPrefix] + private static bool Prefix_Parse_DynamicProperties(XElement elementProperty) + { + if (elementProperty.Name.LocalName != "property") + return false; + return true; + } + + //MinEventParams workarounds + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.fireShot))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_fireShot_ItemActionRanged(IEnumerable instructions) + { + var codes = new List(instructions); + + var fld_ranged_tag = AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.RangedTag)); + var fld_params = AccessTools.Field(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_ranged_tag)) + { + if (!codes[i + 3].LoadsField(fld_params)) + { + codes.InsertRange(i + 2, new CodeInstruction[] + { + new CodeInstruction(OpCodes.Ldloc_1), + CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.MinEventContext)), + new CodeInstruction(OpCodes.Dup), + new CodeInstruction(OpCodes.Ldloc, 10), + CodeInstruction.LoadField(typeof(WorldRayHitInfo), nameof(WorldRayHitInfo.hit)), + CodeInstruction.LoadField(typeof(HitInfoDetails), nameof(HitInfoDetails.pos)), + CodeInstruction.StoreField(typeof(MinEventParams), nameof(MinEventParams.Position)), + new CodeInstruction(OpCodes.Ldloc_1), + CodeInstruction.Call(typeof(EntityAlive), nameof(EntityAlive.GetPosition)), + CodeInstruction.StoreField(typeof(MinEventParams), nameof(MinEventParams.StartPosition)) + }); + } + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.OnHoldingUpdate))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_OnHoldingUpdate_ItemActionRanged(IEnumerable instructions) + { + var mtd_release = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.triggerReleased)); + var codes = instructions.ToList(); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_release)) + { + codes[i + 1].labels.Clear(); + codes[i + 1].MoveLabelsFrom(codes[i - 20]); + codes.RemoveRange(i - 20, 21); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.triggerReleased))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_triggerReleased_ItemActionRanged(IEnumerable instructions) + { + var mtd_effect = AccessTools.Method(typeof(IGameManager), nameof(IGameManager.ItemActionEffectsServer)); + var mtd_data = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.getUserData)); + var codes = instructions.ToList(); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_effect)) + { + codes.InsertRange(i, new CodeInstruction[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Callvirt, mtd_data) + }); + codes.RemoveAt(i - 1); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(GameManager), nameof(GameManager.StartGame))] + [HarmonyPrefix] + private static bool Prefix_StartGame_GameManager() + { + CustomEffectEnumManager.InitFinal(); + return true; + } + + [HarmonyPatch(typeof(PassiveEffect), nameof(PassiveEffect.ParsePassiveEffect))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ParsePassiveEffect_PassiveEffect(IEnumerable instructions) + { + var codes = instructions.ToList(); + MethodInfo mtd_enum_parse = AccessTools.Method(typeof(EnumUtils), nameof(EnumUtils.Parse), new[] { typeof(string), typeof(bool) }, new[] { typeof(PassiveEffects) }); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_enum_parse)) + { + codes.Insert(i + 1, CodeInstruction.Call(typeof(CustomEffectEnumManager), nameof(CustomEffectEnumManager.RegisterOrGetEnum), new[] { typeof(string), typeof(bool) }, new[] { typeof(PassiveEffects) })); + codes.RemoveAt(i); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(MinEventActionBase), nameof(MinEventActionBase.ParseXmlAttribute))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ParseXmlAttribute_MinEventActionBase(IEnumerable instructions) + { + var codes = instructions.ToList(); + MethodInfo mtd_enum_parse = AccessTools.Method(typeof(EnumUtils), nameof(EnumUtils.Parse), new[] { typeof(string), typeof(bool) }, new[] { typeof(MinEventTypes) }); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_enum_parse)) + { + codes.Insert(i + 1, CodeInstruction.Call(typeof(CustomEffectEnumManager), nameof(CustomEffectEnumManager.RegisterOrGetEnum), new[] { typeof(string), typeof(bool) }, new[] { typeof(MinEventTypes) })); + codes.RemoveAt(i); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.OnHoldingUpdate))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_OnHoldingUpdate_ItemActionDynamicMelee(IEnumerable instructions) + { + var codes = instructions.ToList(); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Is(OpCodes.Ldc_R4, 0.1f)) + { + codes.RemoveRange(i, 2); + break; + } + } + return codes; + } + + [HarmonyPatch(typeof(ItemActionDynamicMelee), nameof(ItemActionDynamicMelee.canStartAttack))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_canStartAttack_ItemActionDynamicMelee(IEnumerable instructions) + { + var codes = instructions.ToList(); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Is(OpCodes.Ldc_R4, 0.1f)) + { + codes.RemoveRange(i, 2); + break; + } + } + return codes; + } + + /// + /// projectile direct hit damage percent + /// removed due to new explosion damage passives + /// + /// + /// + //[HarmonyPatch(typeof(ProjectileMoveScript), nameof(ProjectileMoveScript.checkCollision))] + //[HarmonyTranspiler] + //private static IEnumerable Transpiler_checkCollision_ProjectileMoveScript(IEnumerable instructions) + //{ + // var codes = instructions.ToList(); + // var fld_strain = AccessTools.Field(typeof(ItemActionLauncher.ItemActionDataLauncher), nameof(ItemActionLauncher.ItemActionDataLauncher.strainPercent)); + // var mtd_block = AccessTools.Method(typeof(ItemActionAttack), nameof(ItemActionAttack.GetDamageBlock)); + + // for (int i = 0; i < codes.Count; i++) + // { + // if (codes[i].LoadsField(fld_strain)) + // { + // codes.InsertRange(i + 1, new CodeInstruction[] + // { + // new CodeInstruction(OpCodes.Ldarg_0), + // CodeInstruction.LoadField(typeof(ProjectileMoveScript), nameof(ProjectileMoveScript.itemValueProjectile)), + // new CodeInstruction(OpCodes.Ldloc_S, 4), + // CodeInstruction.Call(typeof(CommonUtilityPatch), codes[i - 3].Calls(mtd_block) ? nameof(GetProjectileBlockDamagePerc) : nameof(GetProjectileEntityDamagePerc)), + // new CodeInstruction(OpCodes.Mul) + // }); + // } + // } + + // return codes; + //} + + //public static float GetProjectileBlockDamagePerc(ItemValue _itemValue, EntityAlive _holdingEntity) + //{ + // return EffectManager.GetValue(CustomEnums.ProjectileImpactDamagePercentBlock, _itemValue, 1, _holdingEntity, null); + //} + + //public static float GetProjectileEntityDamagePerc(ItemValue _itemValue, EntityAlive _holdingEntity) + //{ + // return EffectManager.GetValue(CustomEnums.ProjectileImpactDamagePercentEntity, _itemValue, 1, _holdingEntity, null); + //} + + /// + /// force tpv crosshair + /// + /// + /// + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.guiDrawCrosshair))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_guiDrawCrosshair_EntityPlayerLocal(IEnumerable instructions) + { + var codes = instructions.ToList(); + + FieldInfo fld_debug = AccessTools.Field(typeof(ItemAction), nameof(ItemAction.ShowDistanceDebugInfo)); + + for ( int i = 0; i < codes.Count; i++ ) + { + if (codes[i].LoadsField(fld_debug)) + { + var label = codes[i - 1].operand; + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.bFirstPersonView)), + new CodeInstruction(OpCodes.Brfalse_S, label) + }); + break; + } + } + + return codes; + } + + /// + /// correctly apply muzzle flash silence with modifications + /// + /// + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.OnModificationsChanged))] + [HarmonyPostfix] + private static void Postfix_OnModificationsChanged_ItemActionRanged(ItemActionData _data) + { + ItemActionRanged.ItemActionDataRanged itemActionDataRanged = _data as ItemActionRanged.ItemActionDataRanged; + if (itemActionDataRanged.SoundStart.Contains("silenced")) + { + itemActionDataRanged.IsFlashSuppressed = true; + } + + //should fix stuck on switching item? + itemActionDataRanged.isReloadCancelled = false; + itemActionDataRanged.isWeaponReloadCancelled = false; + itemActionDataRanged.isReloading = false; + itemActionDataRanged.isWeaponReloading = false; + itemActionDataRanged.isChangingAmmoType = false; + } + + #region item tags modifier + + /// + /// should handle swapping mod + /// first check if the mod to install can be installed after current mod is removed + /// then check if any other mod requires or conflicts current mod + /// + /// + /// + /// + [HarmonyPatch(typeof(XUiC_ItemPartStack), nameof(XUiC_ItemPartStack.CanSwap))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_CanSwap_XUiC_ItemPartStack(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + LocalBuilder lbd_tags_if_remove_prev = generator.DeclareLocal(typeof(FastTags)); + LocalBuilder lbd_tags_if_install_new = generator.DeclareLocal(typeof(FastTags)); + MethodInfo mtd_get_item_class = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.ItemClass)); + MethodInfo mtd_has_any_tags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAnyTags)); + MethodInfo mtd_test_any_set = AccessTools.Method(typeof(FastTags), nameof(FastTags.Test_AnySet)); + FieldInfo fld_mod = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.Modifications)); + FieldInfo fld_installable_tags = AccessTools.Field(typeof(ItemClassModifier), nameof(ItemClassModifier.InstallableTags)); + + for (int i = 3; i < codes.Count; i++) + { + //get current tags + if (codes[i].opcode == OpCodes.Stloc_2) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldloc_1), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(XUiC_ItemPartStack), "itemValue"), + CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTagsAsIfNotInstalled)), + new CodeInstruction(OpCodes.Stloc_S, lbd_tags_if_remove_prev), + new CodeInstruction(OpCodes.Ldloc_1), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTagsAsIfInstalled)), + new CodeInstruction(OpCodes.Stloc_S, lbd_tags_if_install_new) + }); + i += 10; + Log.Out("mod 1!!!"); + } + //replace checking tags + else if (codes[i].Calls(mtd_has_any_tags) && codes[i - 3].opcode == OpCodes.Ldloc_2) + { + if (codes[i - 1].LoadsField(fld_installable_tags) && (codes[i + 1].opcode == OpCodes.Brtrue || codes[i + 1].opcode == OpCodes.Brtrue_S)) + { + var lbl_prev = codes[i + 4].ExtractLabels(); + var lbl_jump = generator.DefineLabel(); + codes[i + 4].WithLabels(lbl_jump); + codes.InsertRange(i + 4, new[] + { + new CodeInstruction(OpCodes.Ldloc_1).WithLabels(lbl_prev), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(XUiC_ItemPartStack), "itemValue"), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.CanSwapMod)), + new CodeInstruction(OpCodes.Brtrue, lbl_jump), + new CodeInstruction(OpCodes.Ldc_I4_0), + new CodeInstruction(OpCodes.Ret) + }); + } + codes[i - 3].opcode = OpCodes.Ldloca_S; + codes[i - 3].operand = lbd_tags_if_remove_prev; + codes[i].opcode = OpCodes.Call; + codes[i].operand = mtd_test_any_set; + Log.Out("mod 2!!!"); + } + } + + return codes; + } + + [HarmonyPatch(typeof(XUiC_ItemCosmeticStack), nameof(XUiC_ItemCosmeticStack.CanSwap))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_CanSwap_XUiC_ItemCosmeticStack(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + LocalBuilder lbd_tags_if_remove_prev = generator.DeclareLocal(typeof(FastTags)); + LocalBuilder lbd_tags_if_install_new = generator.DeclareLocal(typeof(FastTags)); + LocalBuilder lbd_item_being_assembled = generator.DeclareLocal(typeof(ItemValue)); + MethodInfo mtd_get_item_class = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.ItemClass)); + MethodInfo mtd_has_any_tags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAnyTags)); + MethodInfo mtd_test_any_set = AccessTools.Method(typeof(FastTags), nameof(FastTags.Test_AnySet)); + MethodInfo mtd_get_xui = AccessTools.PropertyGetter(typeof(XUiController), nameof(XUiController.xui)); + MethodInfo mtd_get_cur_item = AccessTools.PropertyGetter(typeof(XUiM_AssembleItem), nameof(XUiM_AssembleItem.CurrentItem)); + FieldInfo fld_cos = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.CosmeticMods)); + FieldInfo fld_installable_tags = AccessTools.Field(typeof(ItemClassModifier), nameof(ItemClassModifier.InstallableTags)); + + for (int i = 3; i < codes.Count; i++) + { + //get current tags + if ((codes[i].opcode == OpCodes.Brtrue || codes[i].opcode == OpCodes.Brtrue_S) && codes[i - 1].opcode == OpCodes.Ldloc_0) + { + codes.InsertRange(i + 3, new[] + { + new CodeInstruction(OpCodes.Ldarg_0).MoveLabelsFrom(codes[i + 3]), + new CodeInstruction(OpCodes.Call, mtd_get_xui), + CodeInstruction.LoadField(typeof(XUi), nameof(XUi.AssembleItem)), + new CodeInstruction(OpCodes.Callvirt, mtd_get_cur_item), + CodeInstruction.LoadField(typeof(ItemStack), nameof(ItemStack.itemValue)), + new CodeInstruction(OpCodes.Stloc_S, lbd_item_being_assembled), + new CodeInstruction(OpCodes.Ldloc_S, lbd_item_being_assembled), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(XUiC_ItemCosmeticStack), "itemValue"), + CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTagsAsIfNotInstalled)), + new CodeInstruction(OpCodes.Stloc_S, lbd_tags_if_remove_prev), + new CodeInstruction(OpCodes.Ldloc_S, lbd_item_being_assembled), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTagsAsIfInstalled)), + new CodeInstruction(OpCodes.Stloc_S, lbd_tags_if_install_new) + }); + i += 18; + Log.Out("cos 1!!!"); + } + //replace checking tags + else if (codes[i].Calls(mtd_has_any_tags) && codes[i - 3].Calls(mtd_get_item_class)) + { + if (codes[i - 1].LoadsField(fld_installable_tags) && (codes[i + 1].opcode == OpCodes.Brtrue || codes[i + 1].opcode == OpCodes.Brtrue_S)) + { + var lbl_prev = codes[i + 4].ExtractLabels(); + var lbl_jump = generator.DefineLabel(); + codes[i + 4].WithLabels(lbl_jump); + codes.InsertRange(i + 4, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_item_being_assembled).WithLabels(lbl_prev), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(XUiC_ItemPartStack), "itemValue"), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.CanSwapMod)), + new CodeInstruction(OpCodes.Brtrue, lbl_jump), + new CodeInstruction(OpCodes.Ldc_I4_0), + new CodeInstruction(OpCodes.Ret) + }); + } + codes[i - 8].MoveLabelsTo(codes[i - 3]); + codes[i - 3].opcode = OpCodes.Ldloca_S; + codes[i - 3].operand = lbd_tags_if_remove_prev; + codes[i].opcode = OpCodes.Call; + codes[i].operand = mtd_test_any_set; + codes.RemoveRange(i - 8, 5); + i -= 5; + Log.Out("cos 2!!!"); + } + } + + return codes; + } + + /// + /// check if other mods relies on this one + /// + /// + /// + /// + [HarmonyPatch(typeof(XUiC_ItemPartStack), "CanRemove")] + [HarmonyPostfix] + private static void Postfix_CanRemove_XUiC_ItemPartStack(ref bool __result, XUiC_ItemPartStack __instance) + { + if (__result && __instance.xui?.AssembleItem?.CurrentItem?.itemValue is ItemValue itemValue) + { + ItemClass itemClass = itemValue.ItemClass; + FastTags tagsAfterRemove = LocalItemTagsManager.GetTagsAsIfNotInstalled(itemValue, __instance.itemValue); + if (tagsAfterRemove.IsEmpty) + { + __result = false; + return; + } + + foreach (var mod in itemValue.Modifications) + { + if (mod.IsEmpty()) + continue; + ItemClassModifier modClass = mod.ItemClass as ItemClassModifier; + if (modClass == null || !tagsAfterRemove.Test_AnySet(modClass.InstallableTags) || tagsAfterRemove.Test_AnySet(modClass.DisallowedTags)) + { + __result = false; + return; + } + } + } + } + + [HarmonyPatch(typeof(XUiC_ItemCosmeticStack), "CanRemove")] + [HarmonyPostfix] + private static void Postfix_CanRemove_XUiC_ItemCosmeticStack(ref bool __result, XUiC_ItemCosmeticStack __instance) + { + if (__result && __instance.xui?.AssembleItem?.CurrentItem?.itemValue is ItemValue itemValue) + { + ItemClass itemClass = itemValue.ItemClass; + FastTags tagsAfterRemove = LocalItemTagsManager.GetTagsAsIfNotInstalled(itemValue, __instance.itemValue); + if (tagsAfterRemove.IsEmpty) + { + __result = false; + return; + } + + foreach (var mod in itemValue.CosmeticMods) + { + if (mod.IsEmpty()) + continue; + ItemClassModifier modClass = mod.ItemClass as ItemClassModifier; + if (modClass == null || !tagsAfterRemove.Test_AnySet(modClass.InstallableTags) || tagsAfterRemove.Test_AnySet(modClass.DisallowedTags)) + { + __result = false; + return; + } + } + } + } + + /// + /// should update the gear icon? + /// + /// + /// + /// + [HarmonyPatch(typeof(XUiC_ItemStack), nameof(XUiC_ItemStack.updateLockTypeIcon))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_updateLockTypeIcon_XUiC_ItemStack(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + LocalBuilder lbd_tags = generator.DeclareLocal(typeof(FastTags)); + MethodInfo mtd_has_any_tags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAnyTags)); + MethodInfo mtd_test_any_set = AccessTools.Method(typeof(FastTags), nameof(FastTags.Test_AnySet)); + MethodInfo mtd_get_item_class = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.ItemClass)); + MethodInfo mtd_get_cur_item = AccessTools.PropertyGetter(typeof(XUiM_AssembleItem), nameof(XUiM_AssembleItem.CurrentItem)); + MethodInfo mtd_get_xui = AccessTools.PropertyGetter(typeof(XUiController), nameof(XUiController.xui)); + + for (int i = 3; i < codes.Count; i++) + { + //get current tags + if ((codes[i].opcode == OpCodes.Brfalse_S || codes[i].opcode == OpCodes.Brfalse) && codes[i - 1].Calls(mtd_get_cur_item)) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Call, mtd_get_xui), + CodeInstruction.LoadField(typeof(XUi), nameof(XUi.AssembleItem)), + new CodeInstruction(OpCodes.Callvirt, mtd_get_cur_item), + CodeInstruction.LoadField(typeof(ItemStack), nameof(ItemStack.itemValue)), + CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTags)), + new CodeInstruction(OpCodes.Stloc_S, lbd_tags) + }); + i += 7; + } + //do not touch check on the modification item + else if (codes[i].Calls(mtd_has_any_tags) && codes[i - 3].Calls(mtd_get_item_class)) + { + codes[i].opcode = OpCodes.Call; + codes[i].operand = mtd_test_any_set; + var insert = new CodeInstruction(OpCodes.Ldloca_S, lbd_tags); + codes[i - 8].MoveLabelsTo(insert); + codes.RemoveRange(i - 8, 6); + codes.Insert(i - 8, insert); + i -= 5; + } + } + + return codes; + } + + /// + /// when installing new mod, use modified tags to check for compatibility + /// + /// + /// + /// + [HarmonyPatch(typeof(XUiM_AssembleItem), nameof(XUiM_AssembleItem.AddPartToItem))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_AddPartToItem_XUiM_AssembleItem(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + LocalBuilder lbd_tags_cur = generator.DeclareLocal(typeof(FastTags)); + LocalBuilder lbd_tags_after_install = generator.DeclareLocal(typeof(FastTags)); + MethodInfo mtd_has_any_tags = AccessTools.Method(typeof(ItemClass), nameof(ItemClass.HasAnyTags)); + MethodInfo mtd_test_any_set = AccessTools.Method(typeof(FastTags), nameof(FastTags.Test_AnySet)); + MethodInfo mtd_get_item_class = AccessTools.PropertyGetter(typeof(ItemValue), nameof(ItemValue.ItemClass)); + MethodInfo mtd_get_cur_item = AccessTools.PropertyGetter(typeof(XUiM_AssembleItem), nameof(XUiM_AssembleItem.CurrentItem)); + MethodInfo mtd_is_empty = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.IsEmpty)); + FieldInfo fld_cos = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.CosmeticMods)); + FieldInfo fld_mod = AccessTools.Field(typeof(ItemValue), nameof(ItemValue.Modifications)); + FieldInfo fld_installable_tags = AccessTools.Field(typeof(ItemClassModifier), nameof(ItemClassModifier.InstallableTags)); + + for (int i = 3; i < codes.Count; i++) + { + //get current tags + if (codes[i].opcode == OpCodes.Stloc_0) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Call, mtd_get_cur_item), + CodeInstruction.LoadField(typeof(ItemStack), nameof(ItemStack.itemValue)), + new CodeInstruction(OpCodes.Dup), + CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTags)), + new CodeInstruction(OpCodes.Stloc_S, lbd_tags_cur), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.GetTagsAsIfInstalled)), + new CodeInstruction(OpCodes.Stloc_S, lbd_tags_after_install) + }); + i += 9; + } + //do not touch check on the modification item, check if current mod can be installed + else if (codes[i].Calls(mtd_has_any_tags) && codes[i - 3].Calls(mtd_get_item_class)) + { + if (codes[i - 1].LoadsField(fld_installable_tags)) + { + codes.InsertRange(i + 2, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Call, mtd_get_cur_item), + CodeInstruction.LoadField(typeof(ItemStack), nameof(ItemStack.itemValue)), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.Call(typeof(LocalItemTagsManager), nameof(LocalItemTagsManager.CanInstallMod)), + new CodeInstruction(OpCodes.Brfalse, codes[i + 1].operand) + }); + } + codes[i].opcode = OpCodes.Call; + codes[i].operand = mtd_test_any_set; + var insert = new CodeInstruction(OpCodes.Ldloca_S, lbd_tags_cur); + codes[i - 6].MoveLabelsTo(insert); + codes.RemoveRange(i - 6, 4); + codes.Insert(i - 6, insert); + i -= 3; + } + } + + return codes; + } + + #endregion + + //change when aiming events are fired + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.SetMoveState))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SetMoveState_EntityPlayerLocal(IEnumerable instructions) + { + var codes = instructions.ToList(); + + FieldInfo fld_msa = AccessTools.Field(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.moveStateAiming)); + + for (int i = 0; i < codes.Count - 2; i++) + { + if (codes[i].LoadsField(fld_msa) && codes[i + 2].opcode == OpCodes.Ldloc_1) + { + codes[i - 2].MoveLabelsTo(codes[i + 13]); + codes.RemoveRange(i - 2, 15); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(EntityAlive), nameof(EntityAlive.AimingGun), MethodType.Setter)] + [HarmonyPrefix] + private static bool Prefix_AimingGun_EntityAlive(bool value, EntityAlive __instance) + { + if (__instance is EntityPlayerLocal && __instance.inventory != null) + { + bool isAimingGun = __instance.AimingGun; + if (value != isAimingGun) + { + __instance.FireEvent(value ? MinEventTypes.onSelfAimingGunStart : MinEventTypes.onSelfAimingGunStop, true); +#if DEBUG + Log.Out(value ? "START AIMING GUN FIRED" : "STOP AIMING GUN FIRED"); +#endif + } + } + return true; + } + + [HarmonyPatch(typeof(ItemActionAttack), nameof(ItemActionAttack.HasRadial))] + [HarmonyPostfix] + private static void Postfix_HasRadial_ItemActionAttack(ref bool __result) + { + EntityPlayerLocal player = GameManager.Instance.World?.GetPrimaryPlayer(); + int index = MultiActionManager.GetActionIndexForEntity(player); + List actionDatas = player.inventory?.holdingItemData?.actionData; + if (actionDatas != null && actionDatas.Count > index && actionDatas[index] is ItemActionRanged.ItemActionDataRanged rangedData && (rangedData.isReloading || rangedData.isWeaponReloading)) + { + __result = false; + } + } + + [HarmonyPatch(typeof(ItemActionAttack), nameof(ItemActionAttack.SetupRadial))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SetupRadial_ItemActionAttack(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + var fld_usable = AccessTools.Field(typeof(ItemClass), nameof(ItemClass.UsableUnderwater)); + + var lbd_states = generator.DeclareLocal(typeof(bool[])); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Stloc_0) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldloc_0), + new CodeInstruction(OpCodes.Ldarg_2), + new CodeInstruction(OpCodes.Ldc_I4_M1), + CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(CommonUtilityPatch.GetUnusableItemEntries)), + new CodeInstruction(OpCodes.Stloc_S, lbd_states) + }); + i += 4; + } + else if (codes[i].LoadsField(fld_usable)) + { + codes.InsertRange(i + 2, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_states).WithLabels(codes[i + 2].ExtractLabels()), + new CodeInstruction(OpCodes.Ldloc_2), + CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(CommonUtilityPatch.IsAmmoDisabled)), + new CodeInstruction(OpCodes.Brtrue_S, codes[i + 1].operand) + }); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemAction), nameof(ItemAction.StartHolding))] + [HarmonyPostfix] + private static void Postfix_StartHolding_ItemAction(ItemActionData _data, ItemAction __instance) + { + if (__instance is ItemActionAttack itemActionAttack && _data.invData.holdingEntity is EntityPlayerLocal player) + { + var arr_disabled_ammo = GetUnusableItemEntries(itemActionAttack.MagazineItemNames, player, _data.indexInEntityOfAction); + if (arr_disabled_ammo == null) + { + return; + } + var itemValue = _data.invData.itemValue; + int cur_index = itemValue.GetSelectedAmmoIndexByActionIndex(_data.indexInEntityOfAction); + if (arr_disabled_ammo[cur_index]) + { + int first_enabled_index = Mathf.Max(Array.IndexOf(arr_disabled_ammo, false), 0); + + var mapping = MultiActionManager.GetMappingForEntity(player.entityId); + if (mapping != null) + { + if (_data.indexInEntityOfAction == mapping.CurMetaIndex) + { + itemValue.SelectedAmmoTypeIndex = (byte)first_enabled_index; + } + else + { + itemValue.SetMetadata(MultiActionUtils.ActionSelectedAmmoNames[mapping.indices.GetMetaIndexForActionIndex(_data.indexInEntityOfAction)], first_enabled_index, TypedMetadataValue.TypeTag.Integer); + } + _data.invData.holdingEntity.inventory.CallOnToolbeltChangedInternal(); + } + else + { + itemValue.SelectedAmmoTypeIndex = (byte)(first_enabled_index); + } + } + } + } + + public static bool[] GetUnusableItemEntries(string[] ammoNames, EntityPlayerLocal player, int actionIndex = -1) + { + if (ammoNames == null) + { + return null; + } + if (actionIndex < 0) + { + actionIndex = MultiActionManager.GetActionIndexForEntity(player); + } + string str_disabled_ammo_names = player.inventory.holdingItemItemValue.GetPropertyOverrideForAction("DisableAmmo", "", actionIndex); + //Log.Out($"checking disabled ammo: {str_disabled_ammo_names}\n{StackTraceUtility.ExtractStackTrace()}"); + bool[] arr_disable_states = new bool[ammoNames.Length]; + if(!string.IsNullOrEmpty(str_disabled_ammo_names)) + { + string[] arr_disabled_ammo_names = str_disabled_ammo_names.Split(',', StringSplitOptions.RemoveEmptyEntries); + foreach (var name in arr_disabled_ammo_names) + { + int index = Array.IndexOf(ammoNames, name.Trim()); + if (index >= 0) + { + arr_disable_states[index] = true; + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"ammo {ammoNames[index]} is disabled"); + } + } + } + return arr_disable_states; + } + + private static bool IsAmmoDisabled(bool[] ammoStates, int index) + { + if (ammoStates == null || ammoStates.Length <= index) + { + return false; + } + return ammoStates[index]; + } + + //dont spread onSelfItemActivate/onSelfItemDeactivate to attachments + //handle start holding + [HarmonyPatch(typeof(Inventory), nameof(Inventory.syncHeldItem))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_syncHeldItem_Inventory(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var prop_itemvalue = AccessTools.PropertyGetter(typeof(Inventory), nameof(Inventory.holdingItemItemValue)); + var mtd_fireevent = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.FireEvent)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_fireevent) && codes[i - 5].Calls(prop_itemvalue)) + { + codes[i] = CodeInstruction.Call(typeof(MinEffectController), nameof(MinEffectController.FireEvent)); + codes.InsertRange(i - 4, new[] + { + CodeInstruction.Call(typeof(ItemValue), "get_ItemClass"), + CodeInstruction.LoadField(typeof(ItemClass), nameof(ItemClass.Effects)) + }); + i += 2; + } + } + + return codes; + } + + //handle radial activation + [HarmonyPatch(typeof(XUiC_Radial), nameof(XUiC_Radial.handleActivatableItemCommand))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_handleActivatableItemCommand_XUiC_Radial(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_fireevent = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.FireEvent)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_fireevent)) + { + codes[i] = CodeInstruction.Call(typeof(MinEffectController), nameof(MinEffectController.FireEvent)); + codes.InsertRange(i - 2, new[] + { + CodeInstruction.Call(typeof(ItemValue), "get_ItemClass"), + CodeInstruction.LoadField(typeof(ItemClass), nameof(ItemClass.Effects)) + }); + i += 2; + } + } + return codes; + } + + //handle equipments + [HarmonyPatch(typeof(Equipment), nameof(Equipment.SetSlotItem))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_SetSlotItem_Equipment(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_fireevent = AccessTools.Method(typeof(ItemValue), nameof(ItemValue.FireEvent)); + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_fireevent) && codes[i - 5].opcode == OpCodes.Ldloc_0 && codes[i - 4].OperandIs((int)MinEventTypes.onSelfItemDeactivate)) + { + codes[i] = CodeInstruction.Call(typeof(MinEffectController), nameof(MinEffectController.FireEvent)); + codes.InsertRange(i - 4, new[] + { + CodeInstruction.Call(typeof(ItemValue), "get_ItemClass"), + CodeInstruction.LoadField(typeof(ItemClass), nameof(ItemClass.Effects)) + }); + i += 2; + } + } + return codes; + } + + [HarmonyPatch(typeof(GameManager), nameof(GameManager.DropContentOfLootContainerServer))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_DropContentOfLootContainerServer_GameManager(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var setter_localscale = AccessTools.PropertySetter(typeof(Transform), nameof(Transform.localScale)); + + for (var i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(setter_localscale)) + { + codes.RemoveRange(i - 6, 7); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.onHoldingEntityFired))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_onHoldingEntityFired_ItemActionRanged(IEnumerable instructions) + { + var codes = instructions.ToList(); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Ldc_R4 && codes[i].operand is 5f) + { + codes.RemoveAt(i); + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(CommonUtilityPatch.GetMaxSpread)) + }); + break; + } + } + return codes; + } + + private static float GetMaxSpread(ItemActionData _data) + { + return EffectManager.GetValue(CustomEnums.MaxWeaponSpread, _data.invData.itemValue, 5f, _data.invData.holdingEntity); + } + + [HarmonyPatch(typeof(NetEntityDistributionEntry), nameof(NetEntityDistributionEntry.getSpawnPacket))] + [HarmonyPrefix] + private static bool Prefix_getSpawnPacket_NetEntityDistributionEntry(NetEntityDistributionEntry __instance, ref NetPackage __result) + { + if (__instance.trackedEntity is EntityAlive ea) + { + __result = NetPackageManager.GetPackage().Setup(new EntityCreationData(__instance.trackedEntity, true), (EntityAlive)__instance.trackedEntity); + return false; + } + return true; + } + + [HarmonyPatch(typeof(World), nameof(World.SpawnEntityInWorld))] + [HarmonyPostfix] + private static void Postfix_SpawnEntityInWorld_World(Entity _entity) + { + if (_entity is EntityAlive ea && !ea.isEntityRemote) + { + ea.FireEvent(CustomEnums.onSelfFirstCVarSync); + } + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.ItemActionEffects))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ItemActionEffects_ItemActionRanged(IEnumerable instructions) + { + var codes = instructions.ToList(); + + for (int i = 0; i < codes.Count - 2; i++) + { + if (codes[i].opcode == OpCodes.Ldloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 9 && codes[i + 2].Branches(out _)) + { + codes.InsertRange(i + 3, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, codes[i].operand).WithLabels(codes[i + 3].ExtractLabels()), + CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(AddTmpMuzzleFlash)), + }); + i += 5; + } + else if (codes[i].opcode == OpCodes.Ldloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 12 && codes[i + 2].Branches(out _)) + { + codes.InsertRange(i + 3, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, codes[i].operand).WithLabels(codes[i + 3].ExtractLabels()), + CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(AddTmpMuzzleFlash)), + }); + i += 5; + } + } + return codes; + } + + private static void AddTmpMuzzleFlash(Transform trans) + { + if (trans.TryGetComponent(out var tmp)) + { + tmp.StopAllCoroutines(); + Component.Destroy(tmp); + } + tmp = trans.AddMissingComponent(); + tmp.life = 5f; + } + + [HarmonyPatch(typeof(vp_FPCamera), nameof(vp_FPCamera.UpdateShakes))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_UpdateShakes_vp_FPCamera(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var fld_shake = AccessTools.Field(typeof(vp_FPCamera), nameof(vp_FPCamera.m_Shake)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].StoresField(fld_shake)) + { + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.Call(typeof(CommonUtilityPatch), nameof(CheckShakeNaN)) + }); + break; + } + } + return codes; + } + + private static void CheckShakeNaN(vp_FPCamera fpcamera) + { + if (float.IsNaN(fpcamera.m_Shake.x) || float.IsNaN(fpcamera.m_Shake.y) || float.IsNaN(fpcamera.m_Shake.z)) + { + Log.Warning("Shake1 NaN {0}, time {1}, speed {2}, amp {3}", new object[] + { + fpcamera.m_Shake, + Time.time, + fpcamera.ShakeSpeed, + fpcamera.ShakeAmplitude + }); + fpcamera.ShakeSpeed = 0f; + fpcamera.m_Shake = Vector3.zero; + fpcamera.m_Pitch += -1f; + } + } + + //[HarmonyPatch(typeof(EntityBuffs), nameof(EntityBuffs.AddBuff), typeof(string), typeof(Vector3i), typeof(int), typeof(bool), typeof(bool), typeof(float))] + //[HarmonyPostfix] + //private static void Postfix_AddBuff_EntityBuffs(string _name, EntityBuffs __instance, EntityBuffs.BuffStatus __result, bool _netSync) + //{ + // if (_name.StartsWith("eftZombieRandomArmor") || _name.StartsWith("eftZombieArmor")) + // Log.Out($"AddBuff [{_name}] on entity {__instance.parent.GetDebugName()} should sync {_netSync} result {__result.ToStringCached()}\n{StackTraceUtility.ExtractStackTrace()}"); + //} + + //[HarmonyPatch(typeof(EntityBuffs), nameof(EntityBuffs.RemoveBuff))] + //[HarmonyPostfix] + //private static void Postfix_RemoveBuff_EntityBuffs(string _name, EntityBuffs __instance, bool _netSync) + //{ + // if (_name.StartsWith("eftZombieRandomArmor") || _name.StartsWith("eftZombieArmor")) + // Log.Out($"RemoveBuff [{_name}] on entity {__instance.parent.GetDebugName()} should sync {_netSync}\n{StackTraceUtility.ExtractStackTrace()}"); + //} + + //[HarmonyPatch(typeof(Inventory), nameof(Inventory.Execute))] + //[HarmonyPrefix] + //private static void Prefix_Execute_Inventory(Inventory __instance, int _actionIdx, bool _bReleased, PlayerActionsLocal _playerActions = null) + //{ + // Log.Out($"Execute Inventory holding item {__instance.holdingItem.Name} slot {__instance.holdingItemIdx} action index {_actionIdx} released {_bReleased} is holster delay {__instance.IsHolsterDelayActive()} is unholster delay {__instance.IsUnholsterDelayActive()}"); + //} + + //[HarmonyPatch(typeof(Inventory), nameof(Inventory.updateHoldingItem))] + //[HarmonyTranspiler] + //private static IEnumerable Transpiler_updateHoldingItem_Inventory(IEnumerable instructions) + //{ + // var codes = instructions.ToList(); + + // var mtd_setholdingtrans = AccessTools.Method(typeof(Inventory), nameof(Inventory.setHoldingItemTransfrom)); + // var mtd_showrighthand = AccessTools.Method(typeof(Inventory), nameof(Inventory.ShowRightHand)); + // int insert = -1, take = -1; + + // for (int i = 0; i < codes.Count; i++) + // { + // if (codes[i].Calls(mtd_showrighthand)) + // { + // insert = i + 1; + // } + // else if (codes[i].Calls(mtd_setholdingtrans)) + // { + // take = i - 6; + // } + // } + + // if (take > insert) + // { + // var list_take = codes.GetRange(take, 7); + // codes.RemoveRange(take, 7); + // codes.InsertRange(insert, list_take); + // } + + // return codes; + //} + //private static bool exported = false; + //[HarmonyPatch(typeof(EModelSDCS), nameof(EModelSDCS.createModel))] + //[HarmonyPostfix] + //private static void Postfix_test(EModelSDCS __instance) + //{ + // if (!exported) + // { + // exported = true; + // var objects = new[] { __instance.entity.RootTransform.gameObject.GetComponentsInChildren()[1] }; + // Log.Out($"exporting objs: {objects.Length} avatar {objects[0].avatar.name} is human {objects[0].avatar.isHuman}"); + // FbxExporter07.OnExport(objects, @"E:\Unity Projects\AnimationPlayground\Assets\ExportedProject\example_skinned_mesh_with_bones.fbx"); + // Application.Quit(); + // } + //} +} + diff --git a/Harmony/RecoilPatch.cs b/Harmony/RecoilPatch.cs new file mode 100644 index 0000000..46754c2 --- /dev/null +++ b/Harmony/RecoilPatch.cs @@ -0,0 +1,156 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using UnityEngine; +using CameraShake; +using System; + +[HarmonyPatch] +class RecoilPatch +{ + [HarmonyPatch(typeof(EntityPlayerLocal), "Awake")] + [HarmonyPostfix] + private static void Postfix_Awake_EntityPlayerLocal(EntityPlayerLocal __instance) + { + RecoilManager.InitPlayer(__instance); + } + + [HarmonyPatch(typeof(vp_FPCamera), nameof(vp_FPCamera.LateUpdate))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_LateUpdate_vp_FPCamera(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_update = AccessTools.Method(typeof(vp_FPCamera), nameof(vp_FPCamera.Update3rdPerson)); + var prop_trans = AccessTools.PropertyGetter(typeof(vp_Component), nameof(vp_Component.transform)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_update)) + { + codes.InsertRange(i - 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Call, prop_trans), + CodeInstruction.Call(typeof(KFExtensions), nameof(KFExtensions.AddMissingComponent), new Type[]{ typeof(Transform) }, new Type[]{ typeof(CameraShaker) }), + CodeInstruction.Call(typeof(CameraShaker), nameof(CameraShaker.UpdateShake)) + }); + break; + } + } + + return codes; + } + + [HarmonyPatch(typeof(GameManager), nameof(GameManager.SaveAndCleanupWorld))] + [HarmonyPostfix] + private static void Postfix_SaveAndCleanupWorld_GameManager() + { + RecoilManager.Cleanup(); + } + + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.OnFired))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_OnFired_EntityPlayerLocal(IEnumerable instructions) + { + var codes = instructions.ToList(); + FieldInfo fld_isfpv = AccessTools.Field(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.bFirstPersonView)); + ConstructorInfo mtd_ctor = AccessTools.Constructor(typeof(Vector2), new[] { typeof(float), typeof(float) }); + + for (int i = 0; i < codes.Count - 1; i++) + { + if (codes[i].Is(OpCodes.Call, mtd_ctor) && codes[i + 1].opcode == OpCodes.Ldloc_0) + { + for (int j = i + 1; j < codes.Count - 1; j++) + { + if (codes[j].opcode == OpCodes.Pop && codes[j + 1].opcode == OpCodes.Ldarg_0) + { + codes.RemoveRange(i + 1, j - i); + break; + } + } + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldloca_S, 0), + new CodeInstruction(OpCodes.Ldloca_S, 1), + CodeInstruction.Call(typeof(RecoilPatch), nameof(RecoilPatch.ModifyRecoil)) + }); + i += 4; + } + else if (codes[i].LoadsField(fld_isfpv)) + { + codes.RemoveRange(i + 2, codes.Count - i - 3); + codes.InsertRange(i + 2, new[] + { + new CodeInstruction(OpCodes.Ldloc_0), + new CodeInstruction(OpCodes.Ldloc_1), + CodeInstruction.Call(typeof(RecoilManager), nameof(RecoilManager.AddRecoil)) + }); + break; + } + } + return codes; + } + + private static void ModifyRecoil(EntityPlayerLocal player, ref Vector2 kickHor, ref Vector2 kickVer) + { + float multiplierHor = Mathf.Max(1 - EffectManager.GetValue(CustomEnums.KickDegreeHorizontalModifier, player.inventory.holdingItemItemValue, 0f, player), 0); + float multiplierVer = Mathf.Max(1 - EffectManager.GetValue(CustomEnums.KickDegreeVerticalModifier, player.inventory.holdingItemItemValue, 0f, player), 0); + kickHor *= multiplierHor; + kickVer *= multiplierVer; + } + + [HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_Update_PlayerMoveController(IEnumerable instructions) + { + var codes = instructions.ToList(); + + FieldInfo fld_rotation = AccessTools.Field(typeof(MovementInput), nameof(MovementInput.rotation)); + FieldInfo fld_rx = AccessTools.Field(typeof(Vector3), nameof(Vector3.x)); + FieldInfo fld_ry = AccessTools.Field(typeof(Vector3), nameof(Vector3.y)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_rotation, true)) + { + if (codes[i + 1].LoadsField(fld_rx, true)) + { + for (; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Stind_R4) + { + codes.Insert(i, CodeInstruction.Call(typeof(RecoilManager), nameof(RecoilManager.CompensateX))); + break; + } + } + } + else if (codes[i + 1].LoadsField(fld_ry, true)) + { + for (; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Stind_R4) + { + codes.Insert(i, CodeInstruction.Call(typeof(RecoilManager), nameof(RecoilManager.CompensateY))); + break; + } + } + } + } + } + + return codes; + } + + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.MoveByInput))] + [HarmonyPrefix] + private static bool Prefix_MoveByInput_EntityPlayerLocal() + { + RecoilManager.ApplyRecoil(); + return true; + } +} \ No newline at end of file diff --git a/Harmony/SaveRescuePatches.cs b/Harmony/SaveRescuePatches.cs new file mode 100644 index 0000000..847c4b2 --- /dev/null +++ b/Harmony/SaveRescuePatches.cs @@ -0,0 +1,6 @@ +namespace KFCommonUtilityLib.Harmony +{ + public static class SaveRescuePatches + { + } +} diff --git a/KFAttached/Animation.meta b/KFAttached/Animation.meta new file mode 100644 index 0000000..970dbaa --- /dev/null +++ b/KFAttached/Animation.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0794a4eb6ebfc3a42a72e08a17a475cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/DebugScripts.meta b/KFAttached/Animation/DebugScripts.meta new file mode 100644 index 0000000..1562796 --- /dev/null +++ b/KFAttached/Animation/DebugScripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8e258bfeacfa28e49abe1c883f258a8b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/DebugScripts/AnimatorActionIndexDebug.cs b/KFAttached/Animation/DebugScripts/AnimatorActionIndexDebug.cs new file mode 100644 index 0000000..f42a73e --- /dev/null +++ b/KFAttached/Animation/DebugScripts/AnimatorActionIndexDebug.cs @@ -0,0 +1,35 @@ +using UnityEngine; + +public class AnimatorActionIndexDebug : StateMachineBehaviour +{ + public override void OnStateMachineEnter(Animator animator, int stateMachinePathHash) + { + Log.Out($"StateMachine enter, Animator action index: {animator.GetInteger("ExecutingActionIndex")}"); + } + + public override void OnStateMachineExit(Animator animator, int stateMachinePathHash) + { + Log.Out($"StateMachine exit, Animator action index: {animator.GetInteger("ExecutingActionIndex")}"); + } + + public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + Log.Out($"State entered!"); + } + + public override void OnStateMove(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + if (animator.GetBool("WeaponFire")) + { + Log.Out($"OnStateMove: Fire trigger set, Animator action index: {animator.GetInteger("ExecutingActionIndex")}"); + } + } + + public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + if (animator.GetBool("WeaponFire")) + { + Log.Out($"OnStateUpdate: Fire trigger set, Animator action index: {animator.GetInteger("ExecutingActionIndex")}"); + } + } +} \ No newline at end of file diff --git a/KFAttached/Animation/DebugScripts/AnimatorActionIndexDebug.cs.meta b/KFAttached/Animation/DebugScripts/AnimatorActionIndexDebug.cs.meta new file mode 100644 index 0000000..ac709cd --- /dev/null +++ b/KFAttached/Animation/DebugScripts/AnimatorActionIndexDebug.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c436ffdfb304ce144a66f57ef3e43bc4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours.meta b/KFAttached/Animation/MonoBehaviours.meta new file mode 100644 index 0000000..8b17691 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 90da1ffd0de481442b66207ea3c9263a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimationAimRecoilReferences.cs b/KFAttached/Animation/MonoBehaviours/AnimationAimRecoilReferences.cs new file mode 100644 index 0000000..dcfb689 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationAimRecoilReferences.cs @@ -0,0 +1,32 @@ +using UnityEngine; + +[AddComponentMenu("KFAttachments/Binding Helpers/Animation Aim Recoil References")] +public class AnimationAimRecoilReferences : MonoBehaviour +{ + [SerializeField] + private Transform[] aimRecoilTargets; + private Vector3[] initialPositions; + + private void Start() + { + if (aimRecoilTargets != null) + { + initialPositions = new Vector3[aimRecoilTargets.Length]; + for (int i = 0; i < aimRecoilTargets.Length; i++) + { + initialPositions[i] = aimRecoilTargets[i].localPosition; + } + } + } + + public void Rollback() + { + if (aimRecoilTargets != null) + { + for (int i = 0; i < aimRecoilTargets.Length; i++) + { + aimRecoilTargets[i].localPosition = initialPositions[i]; + } + } + } +} \ No newline at end of file diff --git a/KFAttached/Animation/MonoBehaviours/AnimationAimRecoilReferences.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimationAimRecoilReferences.cs.meta new file mode 100644 index 0000000..a0e11e0 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationAimRecoilReferences.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9ca4c020de5e68b4ca9902d948462df5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimationDelayRender.cs b/KFAttached/Animation/MonoBehaviours/AnimationDelayRender.cs new file mode 100644 index 0000000..5de4518 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationDelayRender.cs @@ -0,0 +1,212 @@ +using System; +using System.Collections; +using System.Collections.Generic; +#if NotEditor +using UniLinq; +#else +using System.Linq; +#endif +using UnityEngine; +using UnityEngine.Jobs; +using Unity.Collections; +using Unity.Jobs; + +[AddComponentMenu("")] +public class AnimationDelayRender : MonoBehaviour +{ +#if NotEditor + [Serializable] + public class TransformTargets + { + public Transform target; + public bool includeChildren; + } + + public struct TransformLocalData + { + public Vector3 localPosition; + public Quaternion localRotation; + public Vector3 localScale; + + public TransformLocalData(Vector3 localPosition, Quaternion localRotation, Vector3 localScale) + { + this.localPosition = localPosition; + this.localRotation = localRotation; + this.localScale = localScale; + } + } + + private struct TransformRestoreJobs : IJobParallelForTransform + { + public NativeArray data; + public void Execute(int index, TransformAccess transform) + { + if (transform.isValid) + { + transform.SetLocalPositionAndRotation(data[index].localPosition, data[index].localRotation); + transform.localScale = data[index].localScale; + } + } + } + + private struct TransformRestoreAndSaveJobs : IJobParallelForTransform + { + public NativeArray data; + public void Execute(int index, TransformAccess transform) + { + if (transform.isValid) + { + TransformLocalData targetData = new TransformLocalData(transform.localPosition, transform.localRotation, transform.localScale); + transform.SetLocalPositionAndRotation(data[index].localPosition, data[index].localRotation); + transform.localScale = data[index].localScale; + data[index] = targetData; + } + } + } + [NonSerialized] + private Transform[] delayTargets; + + private TransformLocalData[] posTargets; + private EntityPlayerLocal player; + + private NativeArray data; + TransformAccessArray transArr; + private JobHandle restoreJob, restoreAndSaveJob; + private bool dataInitialized = false; + + private void Awake() + { +#if NotEditor + player = GameManager.Instance?.World?.GetPrimaryPlayer(); + if (player == null) + { + Destroy(this); + return; + } +#endif + } + + internal void InitializeTarget() + { + var delayTargetsSet = new HashSet(); + foreach (Transform child in transform.GetComponentsInChildren(true).Skip(1)) + { + delayTargetsSet.Add(child); + } + delayTargets = delayTargetsSet.ToArray(); + posTargets = new TransformLocalData[delayTargets.Length]; + ClearNative(); + data = new NativeArray(delayTargets.Length, Allocator.Persistent, NativeArrayOptions.ClearMemory); + transArr = new TransformAccessArray(delayTargets); + } + + private void InitializeData() + { + for (int i = 0; i < delayTargets.Length; i++) + { + Transform target = delayTargets[i]; + if (target) + { + data[i] = new TransformLocalData(target.localPosition, target.localRotation, target.localScale); + } + } + dataInitialized = true; + } + + private void OnEnable() + { + InitializeTarget(); + player.playerCamera?.gameObject.GetOrAddComponent().targets.Add(this); + //var preAnimatorUpdateJob = new TransformRestoreJobs + //{ + // data = data + //}; + //restoreJob = preAnimatorUpdateJob.Schedule(transArr); + StartCoroutine(EndOfFrameCo()); + Log.Out($"Delay render target count: {delayTargets.Length}"); + } + + private void OnDisable() + { + ClearNative(); + player.playerCamera?.gameObject.GetOrAddComponent().targets.Remove(this); + StopAllCoroutines(); + dataInitialized = false; + } + + private void Update() + { + //for (int i = 0; i < delayTargets.Length; i++) + //{ + // Transform target = delayTargets[i]; + // if (target) + // { + // target.localPosition = posTargets[i].localPosition; + // target.localRotation = posTargets[i].localRotation; + // target.localScale = posTargets[i].localScale; + // } + // else + // { + // delayTargets[i] = null; + // } + //} + restoreJob.Complete(); + } + + private void LateUpdate() + { + if (!dataInitialized) + return; + var postAnimationUpdateJob = new TransformRestoreAndSaveJobs + { + data = data + }; + restoreAndSaveJob = postAnimationUpdateJob.Schedule(transArr); + //for (int i = 0; i < delayTargets.Length; i++) + //{ + // Transform target = delayTargets[i]; + // if (target) + // { + // TransformLocalData targetData = new TransformLocalData(target.localPosition, target.localRotation, target.localScale); + // target.localPosition = posTargets[i].localPosition; + // target.localRotation = posTargets[i].localRotation; + // target.localScale = posTargets[i].localScale; + // posTargets[i] = targetData; + // } + // else + // { + // delayTargets[i] = null; + // } + //} + } + + internal void PreCullCallback() + { + restoreAndSaveJob.Complete(); + } + + private IEnumerator EndOfFrameCo() + { + yield return null; + InitializeData(); + while (true) + { + yield return new WaitForEndOfFrame(); + var eofUpdateJob = new TransformRestoreJobs { data = data }; + restoreJob = eofUpdateJob.Schedule(transArr); + } + } + + private void ClearNative() + { + if (data.IsCreated) + { + data.Dispose(); + } + if (transArr.isCreated) + { + transArr.Dispose(); + } + } +#endif +} \ No newline at end of file diff --git a/KFAttached/Animation/MonoBehaviours/AnimationDelayRender.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimationDelayRender.cs.meta new file mode 100644 index 0000000..fff933b --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationDelayRender.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ba593a40bea2734a8fb4ea26a7c290e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimationDelayRenderReference.cs b/KFAttached/Animation/MonoBehaviours/AnimationDelayRenderReference.cs new file mode 100644 index 0000000..43b84f1 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationDelayRenderReference.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +[AddComponentMenu("")] +internal class AnimationDelayRenderReference : MonoBehaviour +{ +#if NotEditor + internal HashSet targets = new HashSet(); + private void OnPreCull() + { + if (targets.Count > 0) + { + foreach (var target in targets) + { + target.PreCullCallback(); + } + } + } +#endif +} diff --git a/KFAttached/Animation/MonoBehaviours/AnimationDelayRenderReference.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimationDelayRenderReference.cs.meta new file mode 100644 index 0000000..2d8784c --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationDelayRenderReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dfa24b0d9ec212f4eb1f00580cfb4212 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimationFiringEvents.cs b/KFAttached/Animation/MonoBehaviours/AnimationFiringEvents.cs new file mode 100644 index 0000000..8c7de5c --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationFiringEvents.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +public class AnimationFiringEvents : MonoBehaviour +{ + [SerializeField] + private ParticleSystem[] mainParticles; + + private void Awake() + { + if (mainParticles == null) + return; + foreach (var ps in mainParticles) + { + ps.gameObject.SetActive(true); + var emission = ps.emission; + emission.enabled = false; + ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); + var main = ps.main; + main.loop = false; + } + } + + public void Fire(int index) + { + if (mainParticles == null || index < 0 || index >= mainParticles.Length) + return; + GameObject root = mainParticles[index].gameObject; + root.BroadcastMessage("OnEnable", SendMessageOptions.DontRequireReceiver); + mainParticles[index].Emit(1); + } +} diff --git a/KFAttached/Animation/MonoBehaviours/AnimationFiringEvents.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimationFiringEvents.cs.meta new file mode 100644 index 0000000..76e3fe3 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationFiringEvents.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2a71dc0034e159458026e1103e44c62 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimationGraphBuilder.cs b/KFAttached/Animation/MonoBehaviours/AnimationGraphBuilder.cs new file mode 100644 index 0000000..380a606 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationGraphBuilder.cs @@ -0,0 +1,381 @@ +#if NotEditor +#endif +using System; +using System.Collections.Generic; +using System.Diagnostics; +using UnityEngine; +using UnityEngine.Animations; +using UnityEngine.Playables; + +[AddComponentMenu("")] +public class AnimationGraphBuilder : MonoBehaviour +{ + public enum ParamInWrapper + { + None, + Vanilla, + Weapon, + Attachments, + Both + } + private Animator animator; + private RuntimeAnimatorController vanillaRuntimeController; + private Avatar vanillaAvatar; + private PlayableGraph graph; + private AnimationLayerMixerPlayable mixer; + private AnimatorControllerPlayable weaponControllerPlayable; + private AnimatorControllerPlayable vanillaControllerPlayable; + private Avatar weaponAvatar; + private AvatarMask weaponMask; + private bool isFpv; + private bool isLocalPlayer = true; + private readonly List graphRelatedBehaviours = new List(); + private AnimatorControllerParameter[] parameters; + private readonly Dictionary paramMapping = new Dictionary(); + private readonly Dictionary paramMappingDebug = new Dictionary(); + //private Animator[] childAnimators = Array.Empty(); + + public bool HasWeaponOverride => graph.IsValid(); + //public AnimatorControllerPlayable VanillaPlayable => vanillaControllerPlayable; + //public AnimatorControllerPlayable WeaponPlayable => weaponControllerPlayable; + public AnimatorControllerParameter[] Parameters => parameters; + private AnimationTargetsAbs CurrentTarget { get; set; } + public IAnimatorWrapper VanillaWrapper { get; private set; } + public IAnimatorWrapper WeaponWrapper { get; private set; } + public AttachmentWrapper AttachmentWrapper { get; private set; } + public static IAnimatorWrapper DummyWrapper { get; } = new AnimatorWrapper(null); +#if NotEditor + public EntityPlayer Player { get; private set; } +#endif + + private void Awake() + { + isFpv = transform.name == "baseRigFP"; + animator = GetComponent(); + animator.logWarnings = false; + VanillaWrapper = new AnimatorWrapper(animator); + WeaponWrapper = new AnimatorWrapper(null); + parameters = animator.parameters; + UpdateParamMapping(); + vanillaAvatar = animator.avatar; +#if NotEditor + vanillaRuntimeController = isFpv ? SDCSUtils.FPAnimController : SDCSUtils.TPAnimController; + isLocalPlayer = (Player = GetComponentInParent()) is EntityPlayerLocal; +#else + vanillaRuntimeController = animator.runtimeAnimatorController; +#endif + } + + private void UpdateParamMapping() + { + paramMapping.Clear(); + paramMappingDebug.Clear(); + var paramList = new List(); + paramList.AddRange(animator.parameters); + for (int i = 0; i < VanillaWrapper.GetParameterCount(); i++) + { + paramMapping.Add(VanillaWrapper.GetParameter(i).nameHash, ParamInWrapper.Vanilla); + paramMappingDebug.Add(VanillaWrapper.GetParameter(i).name, ParamInWrapper.Vanilla); + } + if (WeaponWrapper != null && WeaponWrapper.IsValid) + { + for (int i = 0; i < WeaponWrapper.GetParameterCount(); i++) + { + var param = WeaponWrapper.GetParameter(i); + if (paramMapping.ContainsKey(param.nameHash)) + { + paramMapping[param.nameHash] = ParamInWrapper.Both; + paramMappingDebug[param.name] = ParamInWrapper.Both; + } + else + { + paramMapping.Add(param.nameHash, ParamInWrapper.Weapon); + paramMappingDebug.Add(param.name, ParamInWrapper.Weapon); + paramList.Add(param); + } + } + } + if (AttachmentWrapper != null && AttachmentWrapper.IsValid) + { + foreach (var animator in AttachmentWrapper.animators) + { + for (int i = 0; i < animator.parameterCount; i++) + { + var param = animator.GetParameter(i); + if (!paramMapping.ContainsKey(param.nameHash)) + { + paramMapping[param.nameHash] = ParamInWrapper.Attachments; + paramList.Add(param); + } + } + } + } + parameters = paramList.ToArray(); + } + + public ParamInWrapper GetWrapperRoleByParamHash(int nameHash) + { + if (paramMapping.TryGetValue(nameHash, out var role)) + return role; + return ParamInWrapper.None; + } + + public ParamInWrapper GetWrapperRoleByParamName(string name) + { + if (string.IsNullOrEmpty(name) || !paramMapping.TryGetValue(Animator.StringToHash(name), out var role)) + return ParamInWrapper.None; + return role; + } + + public ParamInWrapper GetWrapperRoleByParam(AnimatorControllerParameter param) + { + if (param == null || !paramMapping.TryGetValue(param.nameHash, out var role)) + return ParamInWrapper.None; + return role; + } + + public void SetChildFloat(int nameHash, float value) + { + if (AttachmentWrapper != null && AttachmentWrapper.IsValid) + { + AttachmentWrapper.SetFloat(nameHash, value); + } + } + + public void SetChildBool(int nameHash, bool value) + { + if (AttachmentWrapper != null && AttachmentWrapper.IsValid) + { + AttachmentWrapper.SetBool(nameHash, value); + } + } + + public void SetChildInteger(int nameHash, int value) + { + if (AttachmentWrapper != null && AttachmentWrapper.IsValid) + { + AttachmentWrapper.SetInteger(nameHash, value); + } + } + + public void SetChildTrigger(int nameHash) + { + if (AttachmentWrapper != null && AttachmentWrapper.IsValid) + { + AttachmentWrapper.SetTrigger(nameHash); + } + } + + public void ResetChildTrigger(int nameHash) + { + if (AttachmentWrapper != null && AttachmentWrapper.IsValid) + { + AttachmentWrapper.ResetTrigger(nameHash); + } + } + + private void InitGraph() + { + animator.runtimeAnimatorController = null; + if (graph.IsValid()) + { + return; + } + + graph = PlayableGraph.Create(); + mixer = AnimationLayerMixerPlayable.Create(graph, 2); + var output = AnimationPlayableOutput.Create(graph, "output", animator); + output.SetSourcePlayable(mixer); + InitVanilla(); + graph.Play(); + } + + private void InitVanilla() + { + vanillaControllerPlayable = AnimatorControllerPlayable.Create(graph, vanillaRuntimeController); + mixer.ConnectInput(0, vanillaControllerPlayable, 0, isFpv ? 0 : 1.0f); + mixer.SetLayerAdditive(0, false); + } + + public void InitWeapon(Transform weaponRoot, RuntimeAnimatorController weaponRuntimeController, AvatarMask weaponMask) + { + InitGraph(); + InitBehaviours(weaponRoot); + weaponAvatar = AvatarBuilder.BuildGenericAvatar(gameObject, "Origin"); + animator.avatar = weaponAvatar; + weaponControllerPlayable = AnimatorControllerPlayable.Create(graph, weaponRuntimeController); + mixer.ConnectInput(1, weaponControllerPlayable, 0, 1.0f); + mixer.SetLayerAdditive(1, false); + if (weaponMask) + { + mixer.SetLayerMaskFromAvatarMask(1, weaponMask); + } + this.weaponMask = weaponMask; + } + + private void DestroyGraph() + { + CleanupBehaviours(); + weaponMask = null; + if (graph.IsValid()) + { + graph.Destroy(); + } + if (animator) + { + animator.runtimeAnimatorController = vanillaRuntimeController; + animator.avatar = vanillaAvatar; + } + } + + private void DestroyWeapon() + { + CleanupBehaviours(); + weaponMask = null; + if (weaponControllerPlayable.IsValid()) + { + mixer.DisconnectInput(1); + weaponControllerPlayable.Destroy(); + } + animator.avatar = vanillaAvatar; + Destroy(weaponAvatar); + animator.runtimeAnimatorController = vanillaRuntimeController; + } + + public void SetCurrentTarget(AnimationTargetsAbs target) + { + if (CurrentTarget == target) + { + UpdateChildAnimatorArray(target); + return; + } + + var sw = new Stopwatch(); + sw.Start(); +#if NotEditor + bool wasCrouching = VanillaWrapper != null && VanillaWrapper.IsValid && VanillaWrapper.GetBool(AvatarController.isCrouchingHash); +#endif + //var rb = animator.transform.AddMissingComponent(); + //rb.enabled = false; + if (CurrentTarget) + { + CurrentTarget.SetEnabled(false); + } + + bool useGraph = target && (target is PlayGraphTargets || (target.ItemTpv && !isFpv)); + if (HasWeaponOverride) + { + if (useGraph) + { + DestroyWeapon(); + } + else + { + DestroyGraph(); + } + } + + CurrentTarget = target; + if (target) + { + target.SetEnabled(true); + } + // Log.Out($"\n#=================Rebuild Start"); + //#if NotEditor + // Log.Out($"Remaining RigLayers on build:\n{string.Join("\n", rb.layers.Select(layer => layer.name))}"); + //#endif + // animator.UnbindAllSceneHandles(); + // animator.UnbindAllStreamHandles(); + // rb.enabled = true; + // animator.Rebind(); + // Log.Out($"#=================Rebuild Finish\n"); + animator.WriteDefaultValues(); + + if (useGraph) + { + VanillaWrapper = new PlayableWrapper(vanillaControllerPlayable); + WeaponWrapper = new PlayableWrapper(weaponControllerPlayable); + } + else + { + VanillaWrapper = new AnimatorWrapper(animator); + if (target) + { + WeaponWrapper = new AnimatorWrapper(target.ItemAnimator); + } + else + { + WeaponWrapper = DummyWrapper; + } + } + + UpdateChildAnimatorArray(target); + UpdateParamMapping(); +#if NotEditor + animator.SetWrappedBool(AvatarController.isCrouchingHash, wasCrouching); + if (isFpv) + { + VanillaWrapper.Play("idle", 0, 0f); + VanillaWrapper.SetInteger(AvatarController.weaponHoldTypeHash, -1); + } + if (wasCrouching && !isFpv && VanillaWrapper.GetLayerCount() > 4) + { + VanillaWrapper.Play("2HGeneric", 4, 0); + } +#endif + sw.Stop(); + Log.Out($"changing animation target to {(target ? target.name : "null")} took {sw.ElapsedMilliseconds}"); + } + + private void UpdateChildAnimatorArray(AnimationTargetsAbs target) + { + Animator[] childAnimators; + if (target && target.ItemCurrentOrDefault) + { + List animators = new List(); + foreach (Transform trans in target.ItemCurrentOrDefault) + { + animators.AddRange(trans.GetComponentsInChildren()); + } + if (target.ItemAnimator) + { + animators.Remove(target.ItemAnimator); + } + childAnimators = animators.ToArray(); + } + else + { + childAnimators = Array.Empty(); + } + AttachmentWrapper = new AttachmentWrapper(childAnimators); + } + + private void InitBehaviours(Transform weaponRoot) + { + foreach (var scripts in weaponRoot.GetComponents()) + { + var behaviour = scripts.Init(transform, isLocalPlayer); + if (behaviour) + { + graphRelatedBehaviours.Add(behaviour); + } + } + } + + private void CleanupBehaviours() + { + foreach (var behaviour in graphRelatedBehaviours) + { + if (behaviour) + { + (behaviour as IPlayableGraphRelated)?.Disable(transform); + } + } + graphRelatedBehaviours.Clear(); + } + + private void OnDisable() + { + SetCurrentTarget(null); + } +} diff --git a/KFAttached/Animation/MonoBehaviours/AnimationGraphBuilder.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimationGraphBuilder.cs.meta new file mode 100644 index 0000000..db29aa2 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationGraphBuilder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 43f465f7371212e4f8ce8241007afd67 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimationProceduralRecoildAbs.cs b/KFAttached/Animation/MonoBehaviours/AnimationProceduralRecoildAbs.cs new file mode 100644 index 0000000..2cdb205 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationProceduralRecoildAbs.cs @@ -0,0 +1,6 @@ +using UnityEngine; + +public abstract class AnimationProceduralRecoildAbs : MonoBehaviour +{ + public abstract void AddRecoil(Vector3 positionMultiplier, Vector3 rotationMultiplier); +} diff --git a/KFAttached/Animation/MonoBehaviours/AnimationProceduralRecoildAbs.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimationProceduralRecoildAbs.cs.meta new file mode 100644 index 0000000..c519f8e --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationProceduralRecoildAbs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ee261f617ba41e469d725bd8f2cb3c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimationRandomRecoil.cs b/KFAttached/Animation/MonoBehaviours/AnimationRandomRecoil.cs new file mode 100644 index 0000000..1b038e7 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationRandomRecoil.cs @@ -0,0 +1,163 @@ +using DG.Tweening; +using Unity.Mathematics; +using UnityEngine; + +[AddComponentMenu("KFAttachments/Binding Helpers/Animation Random Recoil")] +public class AnimationRandomRecoil : AnimationProceduralRecoildAbs, IPlayableGraphRelated +#if UNITY_EDITOR + , ISerializationCallbackReceiver +#endif +{ + [Header("Targets")] + [SerializeField] private Transform target; + [SerializeField, HideInInspector] private string targetName; + [SerializeField] private Transform pivot; + [SerializeField, HideInInspector] private string pivotName; + [Header("Rotation")] + //[SerializeField] private Vector3 minRotation = new Vector3(-5, -2, -2); + //[SerializeField] private Vector3 maxRotation = new Vector3(0, 2, 2); + [SerializeField] private Vector3 randomRotationMin = new Vector3(-3, -1, -1); + [SerializeField] private Vector3 randomRotationMax = new Vector3(-1, 1, 1); + [Header("Kickback")] + //[SerializeField] private Vector3 minKickback = new Vector3(0, 0, -0.05f); + //[SerializeField] private Vector3 maxKickback = new Vector3(0, 0, 0); + [SerializeField] private Vector3 randomKickbackMin = new Vector3(0, 0, -0.025f); + [SerializeField] private Vector3 randomKickbackMax = new Vector3(0, 0, -0.01f); + [Header("Recoil")] + [SerializeField, Range(0, 0.1f)] private float tweenInDuration = 0.04f; + [SerializeField, Range(0, 5)] private float tweenOutDuration = 1.5f; + [Header("Return")] + [SerializeField, Range(1, 5)] private float elasticAmplitude = 1f; + [SerializeField, Range(0, 1)] private float elasticPeriod = 0.5f; + + private Vector3 targetRotation = Vector3.zero; + private Vector3 targetPosition = Vector3.zero; + private Vector3 currentRotation = Vector3.zero; + private Vector3 currentPosition = Vector3.zero; + private Sequence seq; + //private bool isTweeningIn = true; + + public override void AddRecoil(Vector3 positionMultiplier, Vector3 rotationMultiplier) + { + if (target && pivot) + { + targetPosition = Vector3.Scale(KFExtensions.Random(randomKickbackMin, randomKickbackMax), positionMultiplier); + targetRotation = Vector3.Scale(KFExtensions.Random(randomRotationMin, randomRotationMax), rotationMultiplier); + GameObject targetObj = target.gameObject; + RecreateSeq(); + } + } + + private void OnEnable() + { + ResetSeq(); + } + + private void OnDisable() + { + ResetSeq(); + } + + private void ResetSeq() + { + seq?.Rewind(false); + if (target) + { + target.localEulerAngles = Vector3.zero; + target.localPosition = Vector3.zero; + } + } + + private void RecreateSeq() + { + currentPosition = Vector3.zero; + currentRotation = Vector3.zero; + seq?.Kill(false); + seq = DOTween.Sequence() + //.InsertCallback(0, () => isTweeningIn = true) + .Insert(0, DOTween.To(() => currentRotation, (rot) => currentRotation = rot, targetRotation, tweenInDuration).SetEase(Ease.OutCubic)) + .Insert(0, DOTween.To(() => currentPosition, (pos) => currentPosition = pos, targetPosition, tweenInDuration).SetEase(Ease.OutCubic)) + //.InsertCallback(tweenInDuration, () => isTweeningIn = false) + .Insert(tweenInDuration, DOTween.To(() => currentRotation, (rot) => currentRotation = rot, Vector3.zero, tweenOutDuration).SetEase(Ease.OutElastic, elasticAmplitude, elasticPeriod)) + .Insert(tweenInDuration, DOTween.To(() => currentPosition, (rot) => currentPosition = rot, Vector3.zero, tweenOutDuration).SetEase(Ease.OutElastic, elasticAmplitude, elasticPeriod)) + .OnUpdate(UpdateTransform) + .SetAutoKill(true) + .SetRecyclable(); + } + + private void UpdateTransform() + { + if (target) + { + target.localEulerAngles = Vector3.zero; + target.localPosition = Vector3.zero; + target.RotateAroundPivot(pivot, currentRotation); + target.localPosition += currentPosition; + } + + //if (!isTweeningIn) + //{ + // targetRotation = currentRotation; + // targetPosition = currentPosition; + //} + } + + public MonoBehaviour Init(Transform playerAnimatorTrans, bool isLocalPlayer) + { + if (isLocalPlayer) + { + var copy = playerAnimatorTrans.AddMissingComponent(); + copy.enabled = true; + if (target) + { + copy.target = this.target; + } + else + { + copy.target = playerAnimatorTrans.FindInAllChildren(targetName); + } + if (pivot) + { + copy.pivot = pivot; + } + else + { + copy.pivot = playerAnimatorTrans.FindInAllChildren(pivotName); + } + copy.randomRotationMin = this.randomRotationMin; + copy.randomRotationMax = this.randomRotationMax; + copy.randomKickbackMin = this.randomKickbackMin; + copy.randomKickbackMax = this.randomKickbackMax; + copy.tweenInDuration = this.tweenInDuration; + copy.tweenOutDuration = this.tweenOutDuration; + copy.elasticAmplitude = this.elasticAmplitude; + copy.elasticPeriod = this.elasticPeriod; + return copy; + } + return null; + } + + public void Disable(Transform playerAnimatorTrans) + { + enabled = false; + } + +#if UNITY_EDITOR + public void OnBeforeSerialize() + { + if (target) + { + targetName = target.name; + } + if (pivot) + { + pivotName = pivot.name; + } + } + + public void OnAfterDeserialize() + { + + } +#endif +} \ No newline at end of file diff --git a/KFAttached/Animation/MonoBehaviours/AnimationRandomRecoil.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimationRandomRecoil.cs.meta new file mode 100644 index 0000000..6321f3e --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationRandomRecoil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bd683a2a71b72f04f88532f056986903 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimationRandomSound.cs b/KFAttached/Animation/MonoBehaviours/AnimationRandomSound.cs new file mode 100644 index 0000000..a2dd72b --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationRandomSound.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using Random = UnityEngine.Random; + +[AddComponentMenu("KFAttachments/Utils/Animation Random Sound")] +public class AnimationRandomSound : MonoBehaviour, ISerializationCallbackReceiver +{ + [SerializeField] + public List audioSourcesEditor; + [NonSerialized] + private List audioSources; + + [HideInInspector] + [SerializeField] + private List list_groupnames; + [HideInInspector] + [SerializeField] + private List list_clips; + [HideInInspector] + [SerializeField] + private List list_sources; + [HideInInspector] + [SerializeField] + private List list_clip_indices; + [HideInInspector] + [SerializeField] + private int serializedCount = 0; + + public void OnAfterDeserialize() + { + audioSources = new List(); + for (int i = 0; i < serializedCount; i++) + { + int index = (i == 0 ? 0 : list_clip_indices[i - 1]); + int count = list_clip_indices[i] - index; + audioSources.Add(new AudioSourceGroup() + { + groupName = list_groupnames[i], + clips = list_clips.Skip(index).Take(count).ToArray(), + source = list_sources[i], + }); + } + } + + public void OnBeforeSerialize() + { + if (audioSourcesEditor != null && audioSourcesEditor.Count > 0) + { + serializedCount = 0; + list_groupnames = new List(); + list_clips = new List(); + list_clip_indices = new List(); + list_sources = new List(); + for (int i = 0; i < audioSourcesEditor.Count; i++) + { + list_groupnames.Add(audioSourcesEditor[i].groupName); + list_clips.AddRange(audioSourcesEditor[i].clips); + list_sources.Add(audioSourcesEditor[i].source); + list_clip_indices.Add(list_clips.Count); + serializedCount++; + } + } + } + + public void PlayRandomClip(string group) + { + if (audioSources == null) + return; + + //#if NotEditor + // Log.Out($"play random clip {group}, groups: {string.Join("| ", audioSources.Select(g => g.groupName + $"clips: {string.Join(", ", g.clips.Select(c => c.name))}"))}"); + //#endif + AudioSourceGroup asg = null; + foreach (var audioSourceGroup in audioSources) + { + if (audioSourceGroup.groupName == group) + { + asg = audioSourceGroup; + break; + } + } + + if (asg == null) + { + return; + } + + int random = Random.Range(0, asg.clips.Length); + //asg.source.clip = asg.clips[random]; + asg.source.PlayOneShot(asg.clips[random]); + //#if NotEditor + // Log.Out($"play clip {asg.clips[random].name}"); + //#endif + } +} diff --git a/KFAttached/Animation/MonoBehaviours/AnimationRandomSound.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimationRandomSound.cs.meta new file mode 100644 index 0000000..8159dac --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationRandomSound.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 517d2eb7e1af8a740a6f8ae7cb775f5f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimationReloadEvents.cs b/KFAttached/Animation/MonoBehaviours/AnimationReloadEvents.cs new file mode 100644 index 0000000..58d7610 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationReloadEvents.cs @@ -0,0 +1,356 @@ +#if NotEditor +using KFCommonUtilityLib; + +#endif +using System.Collections; +using UnityEngine; + +[AddComponentMenu("KFAttachments/Utils/Animation Reload Events")] +public class AnimationReloadEvents : MonoBehaviour, IPlayableGraphRelated +{ + private void Awake() + { + animator = GetComponent(); +#if NotEditor + player = GetComponentInParent(); +#endif + } + + public void OnReloadFinish() + { + OnReloadAmmo(); + OnReloadEnd(); + } + + public void OnReloadAmmo() + { +#if NotEditor + if (actionData == null || !actionData.isReloading) + { +#if DEBUG + Log.Out($"ANIMATION RELOAD EVENT NOT RELOADING : {actionData?.invData.item.Name ?? "null"}"); +#endif + return; + } + if (!actionData.isReloadCancelled) + { + player.MinEventContext.ItemActionData = actionData; + ItemValue item = ItemClass.GetItem(actionRanged.MagazineItemNames[actionData.invData.itemValue.SelectedAmmoTypeIndex], false); + int magSize = actionRanged.GetMaxAmmoCount(actionData); + actionData.reloadAmount = GetAmmoCountToReload(player, item, magSize); + if (actionData.reloadAmount > 0) + { + actionData.invData.itemValue.Meta = Utils.FastMin(actionData.invData.itemValue.Meta + actionData.reloadAmount, magSize); + if (actionData.invData.item.Properties.Values[ItemClass.PropSoundIdle] != null) + { + actionData.invData.holdingEntitySoundID = -1; + } + } +#if DEBUG + Log.Out($"ANIMATION RELOAD EVENT AMMO : {actionData.invData.item.Name}"); +#endif + } +#endif + } + + public void OnReloadEnd() + { + StopAllCoroutines(); + animator.SetWrappedBool(Animator.StringToHash("Reload"), false); + animator.SetWrappedBool(Animator.StringToHash("IsReloading"), false); + animator.speed = 1f; +#if NotEditor + cancelReloadCo = null; + if (actionData == null || !actionData.isReloading) + { + return; + } + actionData.isReloading = false; + actionData.isWeaponReloading = false; + actionData.invData.holdingEntity.MinEventContext.ItemActionData = actionData; + actionData.invData.holdingEntity.FireEvent(MinEventTypes.onReloadStop, true); + actionData.invData.holdingEntity.OnReloadEnd(); + actionData.invData.holdingEntity.inventory.CallOnToolbeltChangedInternal(); + AnimationAmmoUpdateState.SetAmmoCountForEntity(actionData.invData.holdingEntity, actionData.invData.slotIdx); + actionData.isReloadCancelled = false; + actionData.isWeaponReloadCancelled = false; + actionData.isChangingAmmoType = false; + if (actionData is IModuleContainerFor dataModule) + { + dataModule.Instance.SetCurrentBarrel(actionData.invData.itemValue.Meta); + } +#if DEBUG + Log.Out($"ANIMATION RELOAD EVENT FINISHED : {actionData.invData.item.Name}"); +#endif + actionData = null; +#endif + } + + public void OnPartialReloadEnd() + { +#if NotEditor + if (actionData == null) + { + return; + } + + player.MinEventContext.ItemActionData = actionData; + ItemValue ammo = ItemClass.GetItem(actionRanged.MagazineItemNames[actionData.invData.itemValue.SelectedAmmoTypeIndex], false); + int magSize = (int)EffectManager.GetValue(PassiveEffects.MagazineSize, actionData.invData.itemValue, (float)actionRanged.BulletsPerMagazine, player); + int partialReloadCount = (int)EffectManager.GetValue(CustomEnums.PartialReloadCount, actionData.invData.itemValue, 1, player); + actionData.reloadAmount = GetPartialReloadCount(player, ammo, magSize, partialReloadCount); + if (actionData.reloadAmount > 0) + { + actionData.invData.itemValue.Meta = Utils.FastMin(actionData.invData.itemValue.Meta + actionData.reloadAmount, magSize); + if (actionData.invData.item.Properties.Values[ItemClass.PropSoundIdle] != null) + { + actionData.invData.holdingEntitySoundID = -1; + } + } + AnimationAmmoUpdateState.SetAmmoCountForEntity(actionData.invData.holdingEntity, actionData.invData.slotIdx); + + if (actionData.isReloadCancelled || actionData.isWeaponReloadCancelled || actionData.invData.itemValue.Meta >= magSize || player.GetItemCount(ammo) <= 0) + { + Log.Out("Partial reload finished"); + animator.SetWrappedBool(Animator.StringToHash("IsReloading"), false); + } +#endif + } + +#if NotEditor + //public bool ReloadUpdatedThisFrame => reloadUpdatedThisFrame; + //private bool reloadUpdatedThisFrame = false; + //internal void OnReloadUpdate() + //{ + // reloadUpdatedThisFrame = true; + //} + + //private void OnAnimatorMove() + //{ + // if (actionData != null) + // { + // //if (actionData.isReloading && !reloadUpdatedThisFrame) + // //{ + // // Log.Warning("Animator not sending update msg this frame, reloading is cancelled!"); + // // actionData.isReloadCancelled = true; + // // OnReloadFinish(); + // //} + // } + // else + // { + // //Log.Warning("actionData is null!"); + // } + // reloadUpdatedThisFrame = false; + //} + + public void OnReloadStart(int actionIndex) + { + if (player == null) + { + player = GetComponentInParent(); + } + actionData = player.inventory.holdingItemData.actionData[actionIndex] as ItemActionRanged.ItemActionDataRanged; + actionRanged = (ItemActionRanged)player.inventory.holdingItem.Actions[actionIndex]; + if (actionData == null || actionData.isReloading) + { + return; + } + + if (actionData.invData.item.Properties.Values[ItemClass.PropSoundIdle] != null && actionData.invData.holdingEntitySoundID >= 0) + { + Audio.Manager.Stop(actionData.invData.holdingEntity.entityId, actionData.invData.item.Properties.Values[ItemClass.PropSoundIdle]); + } + actionData.wasAiming = actionData.invData.holdingEntity.AimingGun; + if (actionData.invData.holdingEntity.AimingGun && actionData.invData.item.Actions[1] is ItemActionZoom) + { + actionData.invData.holdingEntity.inventory.Execute(1, false, null); + actionData.invData.holdingEntity.inventory.Execute(1, true, null); + } + if (animator.GetCurrentAnimatorClipInfo(0).Length != 0 && animator.GetCurrentAnimatorClipInfo(0)[0].clip.events.Length == 0) + { + if (actionRanged.SoundReload != null) + { + player.PlayOneShot(actionRanged.SoundReload.Value, false); + } + } + else if (animator.GetNextAnimatorClipInfo(0).Length != 0 && animator.GetNextAnimatorClipInfo(0)[0].clip.events.Length == 0 && actionRanged.SoundReload != null) + { + player.PlayOneShot(actionRanged.SoundReload.Value, false); + } + + ItemValue itemValue = actionData.invData.itemValue; + actionData.invData.holdingEntity.MinEventContext.ItemActionData = actionData; + int magSize = (int)EffectManager.GetValue(PassiveEffects.MagazineSize, itemValue, actionRanged.BulletsPerMagazine, actionData.invData.holdingEntity); + ItemActionLauncher itemActionLauncher = actionRanged as ItemActionLauncher; + if (itemActionLauncher != null && itemValue.Meta < magSize) + { + ItemValue ammoValue = ItemClass.GetItem(actionRanged.MagazineItemNames[itemValue.SelectedAmmoTypeIndex], false); + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"loading ammo {ammoValue.ItemClass.Name}"); + ItemActionLauncher.ItemActionDataLauncher itemActionDataLauncher = actionData as ItemActionLauncher.ItemActionDataLauncher; + if (itemActionDataLauncher.isChangingAmmoType) + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"is changing ammo type {itemActionDataLauncher.isChangingAmmoType}"); + itemActionLauncher.DeleteProjectiles(actionData); + itemActionDataLauncher.isChangingAmmoType = false; + } + int projectileCount = 1; + if (!actionData.invData.holdingEntity.isEntityRemote) + { + projectileCount = (itemActionLauncher.HasInfiniteAmmo(actionData) ? magSize : GetAmmoCount(actionData.invData.holdingEntity, ammoValue, magSize)); + projectileCount *= getProjectileCount(itemActionDataLauncher); + } + int times = 1; + IModuleContainerFor dataModule = actionData as IModuleContainerFor; + if (dataModule != null && dataModule.Instance.oneRoundMultishot) + { + times = dataModule.Instance.roundsPerShot; + } + for (int j = itemActionDataLauncher.projectileInstance.Count; j < projectileCount; j++) + { + for (int i = 0; i < times; i++) + { + if (dataModule != null) + { + itemActionDataLauncher.projectileJoint = dataModule.Instance.projectileJoints[i]; + } + itemActionDataLauncher.projectileInstance.Add(itemActionLauncher.instantiateProjectile(actionData, Vector3.zero)); + } + } + } + actionData.isReloading = true; + actionData.isWeaponReloading = true; + actionData.invData.holdingEntity.FireEvent(MinEventTypes.onReloadStart, true); +#if DEBUG + Log.Out($"ANIMATION EVENT RELOAD START : {actionData.invData.item.Name}"); +#endif + } + + private Coroutine cancelReloadCo = null; + + public void DelayForceCancelReload(float delay) + { + if (cancelReloadCo == null) + cancelReloadCo = StartCoroutine(ForceCancelReloadCo(delay)); + } + + private void OnDisable() + { + if (animator) + { + OnReloadEnd(); + } + } + + private IEnumerator ForceCancelReloadCo(float delay) + { + yield return new WaitForSecondsRealtime(delay); + if (actionData != null && (actionData.isReloading || actionData.isWeaponReloading) && (actionData.isReloadCancelled || actionData.isWeaponReloadCancelled)) + OnReloadEnd(); + cancelReloadCo = null; + } + + public int GetAmmoCountToReload(EntityAlive ea, ItemValue ammo, int modifiedMagazineSize) + { + int meta = actionData.invData.itemValue.Meta; + int target = modifiedMagazineSize - meta; + if (actionRanged.HasInfiniteAmmo(actionData)) + { + if (actionRanged.AmmoIsPerMagazine) + { + return modifiedMagazineSize; + } + return target; + } + + int res = 0; + if (ea.bag.GetItemCount(ammo, -1, -1, true) > 0) + { + if (actionRanged.AmmoIsPerMagazine) + { + return modifiedMagazineSize * ea.bag.DecItem(ammo, 1, false, null); + } + res = ea.bag.DecItem(ammo, target, false, null); + if (res == target) + { + return res; + } + } + + if (actionRanged.AmmoIsPerMagazine) + { + return modifiedMagazineSize * ea.inventory.DecItem(ammo, 1, false, null); + } + + if (ea.inventory.GetItemCount(ammo, false, -1, -1, true) <= 0) + { + return res; + } + return res + actionData.invData.holdingEntity.inventory.DecItem(ammo, target - res, false, null); + } + + public int GetPartialReloadCount(EntityAlive ea, ItemValue ammo, int modifiedMagazineSize, int partialReloadCount) + { + int meta = actionData.invData.itemValue.Meta; + int target = Mathf.Min(partialReloadCount, modifiedMagazineSize - meta); + if (actionRanged.HasInfiniteAmmo(actionData)) + { + return target; + } + + int res = 0; + if (ea.bag.GetItemCount(ammo) > 0) + { + res = ea.bag.DecItem(ammo, target); + if (res == target) + { + return res; + } + } + + if (ea.inventory.GetItemCount(ammo) <= 0) + { + return res; + } + return res + actionData.invData.holdingEntity.inventory.DecItem(ammo, target - res); + } + + public int GetAmmoCount(EntityAlive ea, ItemValue ammo, int modifiedMagazineSize) + { + return Mathf.Min(ea.bag.GetItemCount(ammo, -1, -1, true) + ea.inventory.GetItemCount(ammo, false, -1, -1, true) + actionData.invData.itemValue.Meta, modifiedMagazineSize); + } + + public int getProjectileCount(ItemActionData _data) + { + int rps = 1; + ItemInventoryData invD = _data != null ? _data.invData : null; + if (invD != null) + { + ItemClass item = invD.itemValue != null ? invD.itemValue.ItemClass : null; + rps = (int)EffectManager.GetValue(PassiveEffects.RoundRayCount, invD.itemValue, rps, invD.holdingEntity); + } + return rps > 0 ? rps : 1; + } + + public EntityAlive player; + public ItemActionRanged.ItemActionDataRanged actionData; + public ItemActionRanged actionRanged; +#endif + private Animator animator; + + public MonoBehaviour Init(Transform playerAnimatorTrans, bool isLocalPlayer) + { + var copy = playerAnimatorTrans.AddMissingComponent(); + if (copy) + { + copy.enabled = true; + } + return copy; + } + + public void Disable(Transform playerAnimatorTrans) + { + enabled = false; + } +} diff --git a/KFAttached/Animation/MonoBehaviours/AnimationReloadEvents.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimationReloadEvents.cs.meta new file mode 100644 index 0000000..91dd052 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationReloadEvents.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c245bc8d9e873ae40ac1f6078f9611c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimationSmokeParticle.cs b/KFAttached/Animation/MonoBehaviours/AnimationSmokeParticle.cs new file mode 100644 index 0000000..ae904bb --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationSmokeParticle.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +public class AnimationSmokeParticle : MonoBehaviour +{ + private ParticleSystem ps; + + private void Awake() + { + if (!TryGetComponent(out ps)) + Destroy(this); + } + + private void OnEnable() + { + ps.Clear(true); + } +} diff --git a/KFAttached/Animation/MonoBehaviours/AnimationSmokeParticle.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimationSmokeParticle.cs.meta new file mode 100644 index 0000000..0fe0883 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimationSmokeParticle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 173c51f67c407a94388cc82dddafc06f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimatorWrapper.meta b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper.meta new file mode 100644 index 0000000..13c8ac2 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 74718732aa3d8274fb470008c5d9e819 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AnimatorWrapper.cs b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AnimatorWrapper.cs new file mode 100644 index 0000000..5b7e20d --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AnimatorWrapper.cs @@ -0,0 +1,131 @@ +using System.Collections.Generic; +using UnityEngine; + +public class AnimatorWrapper : IAnimatorWrapper +{ + private Animator animator; + + public bool IsValid => animator; + + public AnimatorWrapper(Animator animator) => this.animator = animator; + + public void CrossFade(string stateName, float transitionDuration) => animator.CrossFade(stateName, transitionDuration); + + public void CrossFade(string stateName, float transitionDuration, int layer) => animator.CrossFade(stateName, transitionDuration, layer); + + public void CrossFade(string stateName, float transitionDuration, int layer, float normalizedTime) => animator.CrossFade(stateName, transitionDuration, layer, normalizedTime); + + public void CrossFade(int stateNameHash, float transitionDuration) => animator.CrossFade(stateNameHash, transitionDuration); + + public void CrossFade(int stateNameHash, float transitionDuration, int layer) => animator.CrossFade(stateNameHash, transitionDuration, layer); + + public void CrossFade(int stateNameHash, float transitionDuration, int layer, float normalizedTime) => animator.CrossFade(stateNameHash, transitionDuration, layer, normalizedTime); + + public void CrossFadeInFixedTime(string stateName, float transitionDuration) => animator.CrossFadeInFixedTime(stateName, transitionDuration); + + public void CrossFadeInFixedTime(string stateName, float transitionDuration, int layer) => animator.CrossFadeInFixedTime(stateName, transitionDuration, layer); + + public void CrossFadeInFixedTime(string stateName, float transitionDuration, int layer, float fixedTime) => animator.CrossFadeInFixedTime(stateName, transitionDuration, layer, fixedTime); + + public void CrossFadeInFixedTime(int stateNameHash, float transitionDuration) => animator.CrossFadeInFixedTime(stateNameHash, transitionDuration); + + public void CrossFadeInFixedTime(int stateNameHash, float transitionDuration, int layer) => animator.CrossFadeInFixedTime(stateNameHash, transitionDuration, layer); + + public void CrossFadeInFixedTime(int stateNameHash, float transitionDuration, int layer, float fixedTime) => animator.CrossFadeInFixedTime(stateNameHash, transitionDuration, layer, fixedTime); + + public AnimatorTransitionInfo GetAnimatorTransitionInfo(int layerIndex) => animator.GetAnimatorTransitionInfo(layerIndex); + + public bool GetBool(string name) => animator.GetBool(name); + + public bool GetBool(int id) => animator.GetBool(id); + + public AnimatorClipInfo[] GetCurrentAnimatorClipInfo(int layerIndex) => animator.GetCurrentAnimatorClipInfo(layerIndex); + + public void GetCurrentAnimatorClipInfo(int layerIndex, List clips) => animator.GetCurrentAnimatorClipInfo(layerIndex, clips); + + public int GetCurrentAnimatorClipInfoCount(int layerIndex) => animator.GetCurrentAnimatorClipInfoCount(layerIndex); + + public AnimatorStateInfo GetCurrentAnimatorStateInfo(int layerIndex) => animator.GetCurrentAnimatorStateInfo(layerIndex); + + public float GetFloat(string name) => animator.GetFloat(name); + + public float GetFloat(int id) => animator.GetFloat(id); + + public int GetInteger(string name) => animator.GetInteger(name); + + public int GetInteger(int id) => animator.GetInteger(id); + + public int GetLayerCount() => animator.layerCount; + + public int GetLayerIndex(string layerName) => animator.GetLayerIndex(layerName); + + public string GetLayerName(int layerIndex) => animator.GetLayerName(layerIndex); + + public float GetLayerWeight(int layerIndex) => animator.GetLayerWeight(layerIndex); + + public void GetNextAnimatorClipInfo(int layerIndex, List clips) => animator.GetNextAnimatorClipInfo(layerIndex, clips); + + public AnimatorClipInfo[] GetNextAnimatorClipInfo(int layerIndex) => animator.GetNextAnimatorClipInfo(layerIndex); + + public int GetNextAnimatorClipInfoCount(int layerIndex) => animator.GetNextAnimatorClipInfoCount(layerIndex); + + public AnimatorStateInfo GetNextAnimatorStateInfo(int layerIndex) => animator.GetNextAnimatorStateInfo(layerIndex); + + public AnimatorControllerParameter GetParameter(int index) => animator.GetParameter(index); + + public int GetParameterCount() => animator.parameterCount; + + public bool HasState(int layerIndex, int stateID) => animator.HasState(layerIndex, stateID); + + public bool IsInTransition(int layerIndex) => animator.IsInTransition(layerIndex); + + public bool IsParameterControlledByCurve(string name) => animator.IsParameterControlledByCurve(name); + + public bool IsParameterControlledByCurve(int id) => animator.IsParameterControlledByCurve(id); + + public void Play(string stateName) => animator.Play(stateName); + + public void Play(string stateName, int layer) => animator.Play(stateName, layer); + + public void Play(string stateName, int layer, float normalizedTime) => animator.Play(stateName, layer, normalizedTime); + + public void Play(int stateNameHash) => animator.Play(stateNameHash); + + public void Play(int stateNameHash, int layer) => animator.Play(stateNameHash, layer); + + public void Play(int stateNameHash, int layer, float normalizedTime) => animator.Play(stateNameHash, layer, normalizedTime); + + public void PlayInFixedTime(string stateName) => animator.PlayInFixedTime(stateName); + + public void PlayInFixedTime(string stateName, int layer) => animator.PlayInFixedTime(stateName, layer); + + public void PlayInFixedTime(string stateName, int layer, float fixedTime) => animator.PlayInFixedTime(stateName, layer, fixedTime); + + public void PlayInFixedTime(int stateNameHash) => animator.PlayInFixedTime(stateNameHash); + + public void PlayInFixedTime(int stateNameHash, int layer) => animator.PlayInFixedTime(stateNameHash, layer); + + public void PlayInFixedTime(int stateNameHash, int layer, float fixedTime) => animator.PlayInFixedTime(stateNameHash, layer, fixedTime); + + public void ResetTrigger(string name) => animator.ResetTrigger(name); + + public void ResetTrigger(int id) => animator.ResetTrigger(id); + + public void SetBool(string name, bool value) => animator.SetBool(name, value); + + public void SetBool(int id, bool value) => animator.SetBool(id, value); + + public void SetFloat(string name, float value) => animator.SetFloat(name, value); + + public void SetFloat(int id, float value) => animator.SetFloat(id, value); + + public void SetInteger(string name, int value) => animator.SetInteger(name, value); + + public void SetInteger(int id, int value) => animator.SetInteger(id, value); + + public void SetLayerWeight(int layerIndex, float weight) => animator.SetLayerWeight(layerIndex, weight); + + public void SetTrigger(string name) => animator.SetTrigger(name); + + public void SetTrigger(int id) => animator.SetTrigger(id); +} \ No newline at end of file diff --git a/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AnimatorWrapper.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AnimatorWrapper.cs.meta new file mode 100644 index 0000000..127d6d2 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AnimatorWrapper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 330523dd2a309f042a9aafdb565149c5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AttachmentWrapper.cs b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AttachmentWrapper.cs new file mode 100644 index 0000000..f43abac --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AttachmentWrapper.cs @@ -0,0 +1,443 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +public class AttachmentWrapper : IAnimatorWrapper +{ + public Animator[] animators; + public AttachmentWrapper(Animator[] animators) + { + this.animators = animators; + } + + public bool IsValid => animators != null && animators.Length > 0; + + public void CrossFade(string stateName, float transitionDuration) + { + foreach (var animator in animators) + { + animator.CrossFade(stateName, transitionDuration); + } + } + + public void CrossFade(string stateName, float transitionDuration, int layer) + { + foreach (var animator in animators) + { + animator.CrossFade(stateName, transitionDuration, layer); + } + } + + public void CrossFade(string stateName, float transitionDuration, int layer, float normalizedTime) + { + foreach (var animator in animators) + { + animator.CrossFade(stateName, transitionDuration, layer, normalizedTime); + } + } + + public void CrossFade(int stateNameHash, float transitionDuration) + { + foreach (var animator in animators) + { + animator.CrossFade(stateNameHash, transitionDuration); + } + } + + public void CrossFade(int stateNameHash, float transitionDuration, int layer) + { + foreach (var animator in animators) + { + animator.CrossFade(stateNameHash, transitionDuration, layer); + } + } + + public void CrossFade(int stateNameHash, float transitionDuration, int layer, float normalizedTime) + { + foreach (var animator in animators) + { + animator.CrossFade(stateNameHash, transitionDuration, layer, normalizedTime); + } + } + + public void CrossFadeInFixedTime(string stateName, float transitionDuration) + { + foreach (var animator in animators) + { + animator.CrossFadeInFixedTime(stateName, transitionDuration); + } + } + + public void CrossFadeInFixedTime(string stateName, float transitionDuration, int layer) + { + foreach (var animator in animators) + { + animator.CrossFadeInFixedTime(stateName, transitionDuration, layer); + } + } + + public void CrossFadeInFixedTime(string stateName, float transitionDuration, int layer, float fixedTime) + { + foreach (var animator in animators) + { + animator.CrossFadeInFixedTime(stateName, transitionDuration, layer, fixedTime); + } + } + + public void CrossFadeInFixedTime(int stateNameHash, float transitionDuration) + { + foreach (var animator in animators) + { + animator.CrossFadeInFixedTime(stateNameHash, transitionDuration); + } + } + + public void CrossFadeInFixedTime(int stateNameHash, float transitionDuration, int layer) + { + foreach (var animator in animators) + { + animator.CrossFadeInFixedTime(stateNameHash, transitionDuration, layer); + } + } + + public void CrossFadeInFixedTime(int stateNameHash, float transitionDuration, int layer, float fixedTime) + { + foreach (var animator in animators) + { + animator.CrossFadeInFixedTime(stateNameHash, transitionDuration, layer, fixedTime); + } + } + + public AnimatorTransitionInfo GetAnimatorTransitionInfo(int layerIndex) + { + return animators[0].GetAnimatorTransitionInfo(layerIndex); + } + + public bool GetBool(string name) + { + return GetBool(Animator.StringToHash(name)); + } + + public bool GetBool(int id) + { + foreach (var animator in animators) + { + if (animator.GetBool(id)) + return true; + } + return false; + } + + public AnimatorClipInfo[] GetCurrentAnimatorClipInfo(int layerIndex) + { + return animators[0].GetCurrentAnimatorClipInfo(layerIndex); + } + + public void GetCurrentAnimatorClipInfo(int layerIndex, List clips) + { + animators[0].GetCurrentAnimatorClipInfo(layerIndex, clips); + } + + public int GetCurrentAnimatorClipInfoCount(int layerIndex) + { + return animators[0].GetCurrentAnimatorClipInfoCount(layerIndex); + } + + public AnimatorStateInfo GetCurrentAnimatorStateInfo(int layerIndex) + { + return animators[0].GetCurrentAnimatorStateInfo(layerIndex); + } + + public float GetFloat(string name) + { + return GetFloat(Animator.StringToHash(name)); + } + + public float GetFloat(int id) + { + foreach (var animator in animators) + { + float value = animator.GetFloat(id); + if (value != 0) + { + return value; + } + } + return 0; + } + + public int GetInteger(string name) + { + return GetInteger(Animator.StringToHash(name)); + } + + public int GetInteger(int id) + { + foreach (var animator in animators) + { + int value = animator.GetInteger(id); + if (value != 0) + { + return value; + } + } + return 0; + } + + public int GetLayerCount() + { + return animators[0].layerCount; + } + + public int GetLayerIndex(string layerName) + { + return animators[0].GetLayerIndex(layerName); + } + + public string GetLayerName(int layerIndex) + { + return animators[0].GetLayerName(layerIndex); + } + + public float GetLayerWeight(int layerIndex) + { + return animators[0].GetLayerWeight(layerIndex); + } + + public void GetNextAnimatorClipInfo(int layerIndex, List clips) + { + animators[0].GetNextAnimatorClipInfo(layerIndex, clips); + } + + public AnimatorClipInfo[] GetNextAnimatorClipInfo(int layerIndex) + { + return animators[0].GetNextAnimatorClipInfo(layerIndex); + } + + public int GetNextAnimatorClipInfoCount(int layerIndex) + { + return animators[0].GetNextAnimatorClipInfoCount(layerIndex); + } + + public AnimatorStateInfo GetNextAnimatorStateInfo(int layerIndex) + { + return animators[0].GetNextAnimatorStateInfo(layerIndex); + } + + public AnimatorControllerParameter GetParameter(int index) + { + return animators[0].GetParameter(index); + } + + public int GetParameterCount() + { + return animators[0].parameterCount; + } + + public bool HasState(int layerIndex, int stateID) + { + return animators[0].HasState(layerIndex, stateID); + } + + public bool IsInTransition(int layerIndex) + { + return animators[0].IsInTransition(layerIndex); + } + + public bool IsParameterControlledByCurve(string name) + { + return animators[0].IsParameterControlledByCurve(name); + } + + public bool IsParameterControlledByCurve(int id) + { + return animators[0].IsParameterControlledByCurve(id); + } + + public void Play(string stateName) + { + foreach (var animator in animators) + { + animator.Play(stateName); + } + } + + public void Play(string stateName, int layer) + { + foreach (var animator in animators) + { + animator.Play(stateName, layer); + } + } + + public void Play(string stateName, int layer, float normalizedTime) + { + foreach (var animator in animators) + { + animator.Play(stateName, layer, normalizedTime); + } + } + + public void Play(int stateNameHash) + { + foreach (var animator in animators) + { + animator.Play(stateNameHash); + } + } + + public void Play(int stateNameHash, int layer) + { + foreach (var animator in animators) + { + animator.Play(stateNameHash, layer); + } + } + + public void Play(int stateNameHash, int layer, float normalizedTime) + { + foreach (var animator in animators) + { + animator.Play(stateNameHash, layer, normalizedTime); + } + } + + public void PlayInFixedTime(string stateName) + { + foreach (var animator in animators) + { + animator.PlayInFixedTime(stateName); + } + } + + public void PlayInFixedTime(string stateName, int layer) + { + foreach (var animator in animators) + { + animator.PlayInFixedTime(stateName, layer); + } + } + + public void PlayInFixedTime(string stateName, int layer, float fixedTime) + { + foreach (var animator in animators) + { + animator.PlayInFixedTime(stateName, layer, fixedTime); + } + } + + public void PlayInFixedTime(int stateNameHash) + { + foreach (var animator in animators) + { + animator.PlayInFixedTime(stateNameHash); + } + } + + public void PlayInFixedTime(int stateNameHash, int layer) + { + foreach (var animator in animators) + { + animator.PlayInFixedTime(stateNameHash, layer); + } + } + + public void PlayInFixedTime(int stateNameHash, int layer, float fixedTime) + { + foreach (var animator in animators) + { + animator.PlayInFixedTime(stateNameHash, layer, fixedTime); + } + } + + public void ResetTrigger(string name) + { + foreach (var animator in animators) + { + animator.ResetTrigger(name); + } + } + + public void ResetTrigger(int id) + { + foreach (var animator in animators) + { + animator.ResetTrigger(id); + } + } + + public void SetBool(string name, bool value) + { + foreach (var animator in animators) + { + animator.SetBool(name, value); + } + } + + public void SetBool(int id, bool value) + { + foreach (var animator in animators) + { + animator.SetBool(id, value); + } + } + + public void SetFloat(string name, float value) + { + foreach (var animator in animators) + { + animator.SetFloat(name, value); + } + } + + public void SetFloat(int id, float value) + { + foreach (var animator in animators) + { + animator.SetFloat(id, value); + } + } + + public void SetInteger(string name, int value) + { + foreach (var animator in animators) + { + animator.SetInteger(name, value); + } + } + + public void SetInteger(int id, int value) + { + foreach (var animator in animators) + { + animator.SetInteger(id, value); + } + } + + public void SetLayerWeight(int layerIndex, float weight) + { + foreach (var animator in animators) + { + animator.SetLayerWeight(layerIndex, weight); + } + } + + public void SetTrigger(string name) + { + foreach (var animator in animators) + { + animator.SetTrigger(name); + } + } + + public void SetTrigger(int id) + { + foreach (var animator in animators) + { + animator.SetTrigger(id); + } + } +} diff --git a/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AttachmentWrapper.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AttachmentWrapper.cs.meta new file mode 100644 index 0000000..ef17a9e --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/AttachmentWrapper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9aff1989baed1884fb65a80108d5ab68 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/PlayableWrapper.cs b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/PlayableWrapper.cs new file mode 100644 index 0000000..7ef959f --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/PlayableWrapper.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Animations; +using UnityEngine.Playables; + +public class PlayableWrapper : IAnimatorWrapper +{ + private AnimatorControllerPlayable playable; + + public PlayableWrapper(AnimatorControllerPlayable playable) + { + this.playable = playable; + } + + public bool IsValid => playable.IsValid(); + + public float GetFloat(string name) => playable.GetFloat(name); + public float GetFloat(int id) => playable.GetFloat(id); + public void SetFloat(string name, float value) => playable.SetFloat(name, value); + public void SetFloat(int id, float value) => playable.SetFloat(id, value); + + public bool GetBool(string name) => playable.GetBool(name); + public bool GetBool(int id) => playable.GetBool(id); + public void SetBool(string name, bool value) => playable.SetBool(name, value); + public void SetBool(int id, bool value) => playable.SetBool(id, value); + + public int GetInteger(string name) => playable.GetInteger(name); + public int GetInteger(int id) => playable.GetInteger(id); + public void SetInteger(string name, int value) => playable.SetInteger(name, value); + public void SetInteger(int id, int value) => playable.SetInteger(id, value); + + public void SetTrigger(string name) => playable.SetTrigger(name); + public void SetTrigger(int id) => playable.SetTrigger(id); + public void ResetTrigger(string name) => playable.ResetTrigger(name); + public void ResetTrigger(int id) => playable.ResetTrigger(id); + + public bool IsParameterControlledByCurve(string name) => playable.IsParameterControlledByCurve(name); + public bool IsParameterControlledByCurve(int id) => playable.IsParameterControlledByCurve(id); + + public int GetLayerCount() => playable.GetLayerCount(); + public string GetLayerName(int layerIndex) => playable.GetLayerName(layerIndex); + public int GetLayerIndex(string layerName) => playable.GetLayerIndex(layerName); + public float GetLayerWeight(int layerIndex) => playable.GetLayerWeight(layerIndex); + public void SetLayerWeight(int layerIndex, float weight) => playable.SetLayerWeight(layerIndex, weight); + + public AnimatorStateInfo GetCurrentAnimatorStateInfo(int layerIndex) => playable.GetCurrentAnimatorStateInfo(layerIndex); + public AnimatorStateInfo GetNextAnimatorStateInfo(int layerIndex) => playable.GetNextAnimatorStateInfo(layerIndex); + public AnimatorTransitionInfo GetAnimatorTransitionInfo(int layerIndex) => playable.GetAnimatorTransitionInfo(layerIndex); + + public AnimatorClipInfo[] GetCurrentAnimatorClipInfo(int layerIndex) => playable.GetCurrentAnimatorClipInfo(layerIndex); + public void GetCurrentAnimatorClipInfo(int layerIndex, List clips) => playable.GetCurrentAnimatorClipInfo(layerIndex, clips); + public void GetNextAnimatorClipInfo(int layerIndex, List clips) => playable.GetNextAnimatorClipInfo(layerIndex, clips); + public int GetCurrentAnimatorClipInfoCount(int layerIndex) => playable.GetCurrentAnimatorClipInfoCount(layerIndex); + public int GetNextAnimatorClipInfoCount(int layerIndex) => playable.GetNextAnimatorClipInfoCount(layerIndex); + public AnimatorClipInfo[] GetNextAnimatorClipInfo(int layerIndex) => playable.GetNextAnimatorClipInfo(layerIndex); + + public bool IsInTransition(int layerIndex) => playable.IsInTransition(layerIndex); + + public int GetParameterCount() => playable.GetParameterCount(); + public AnimatorControllerParameter GetParameter(int index) => playable.GetParameter(index); + + public void CrossFadeInFixedTime(string stateName, float transitionDuration) => playable.CrossFadeInFixedTime(stateName, transitionDuration); + public void CrossFadeInFixedTime(string stateName, float transitionDuration, int layer) => playable.CrossFadeInFixedTime(stateName, transitionDuration, layer); + public void CrossFadeInFixedTime(string stateName, float transitionDuration, int layer, float fixedTime) => playable.CrossFadeInFixedTime(stateName, transitionDuration, layer, fixedTime); + public void CrossFadeInFixedTime(int stateNameHash, float transitionDuration) => playable.CrossFadeInFixedTime(stateNameHash, transitionDuration); + public void CrossFadeInFixedTime(int stateNameHash, float transitionDuration, int layer) => playable.CrossFadeInFixedTime(stateNameHash, transitionDuration, layer); + public void CrossFadeInFixedTime(int stateNameHash, float transitionDuration, int layer, float fixedTime) => playable.CrossFadeInFixedTime(stateNameHash, transitionDuration, layer, fixedTime); + + public void CrossFade(string stateName, float transitionDuration) => playable.CrossFade(stateName, transitionDuration); + public void CrossFade(string stateName, float transitionDuration, int layer) => playable.CrossFade(stateName, transitionDuration, layer); + public void CrossFade(string stateName, float transitionDuration, int layer, float normalizedTime) => playable.CrossFade(stateName, transitionDuration, layer, normalizedTime); + public void CrossFade(int stateNameHash, float transitionDuration) => playable.CrossFade(stateNameHash, transitionDuration); + public void CrossFade(int stateNameHash, float transitionDuration, int layer) => playable.CrossFade(stateNameHash, transitionDuration, layer); + public void CrossFade(int stateNameHash, float transitionDuration, int layer, float normalizedTime) => playable.CrossFade(stateNameHash, transitionDuration, layer, normalizedTime); + + public void PlayInFixedTime(string stateName) => playable.PlayInFixedTime(stateName); + public void PlayInFixedTime(string stateName, int layer) => playable.PlayInFixedTime(stateName, layer); + public void PlayInFixedTime(string stateName, int layer, float fixedTime) => playable.PlayInFixedTime(stateName, layer, fixedTime); + public void PlayInFixedTime(int stateNameHash) => playable.PlayInFixedTime(stateNameHash); + public void PlayInFixedTime(int stateNameHash, int layer) => playable.PlayInFixedTime(stateNameHash, layer); + public void PlayInFixedTime(int stateNameHash, int layer, float fixedTime) => playable.PlayInFixedTime(stateNameHash, layer, fixedTime); + + public void Play(string stateName) => playable.Play(stateName); + public void Play(string stateName, int layer) => playable.Play(stateName, layer); + public void Play(string stateName, int layer, float normalizedTime) => playable.Play(stateName, layer, normalizedTime); + public void Play(int stateNameHash) => playable.Play(stateNameHash); + public void Play(int stateNameHash, int layer) => playable.Play(stateNameHash, layer); + public void Play(int stateNameHash, int layer, float normalizedTime) => playable.Play(stateNameHash, layer, normalizedTime); + + public bool HasState(int layerIndex, int stateID) => playable.HasState(layerIndex, stateID); +} + diff --git a/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/PlayableWrapper.cs.meta b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/PlayableWrapper.cs.meta new file mode 100644 index 0000000..cce2821 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/AnimatorWrapper/PlayableWrapper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: af94698a131639a4ba070db09410d746 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/IAnimatorWrapper.cs b/KFAttached/Animation/MonoBehaviours/IAnimatorWrapper.cs new file mode 100644 index 0000000..11699af --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/IAnimatorWrapper.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using UnityEngine.Animations; +using UnityEngine.Playables; + +public interface IAnimatorWrapper +{ + bool IsValid { get; } + float GetFloat(string name); + float GetFloat(int id); + void SetFloat(string name, float value); + void SetFloat(int id, float value); + bool GetBool(string name); + bool GetBool(int id); + void SetBool(string name, bool value); + void SetBool(int id, bool value); + int GetInteger(string name); + int GetInteger(int id); + void SetInteger(string name, int value); + void SetInteger(int id, int value); + void SetTrigger(string name); + void SetTrigger(int id); + void ResetTrigger(string name); + void ResetTrigger(int id); + bool IsParameterControlledByCurve(string name); + bool IsParameterControlledByCurve(int id); + int GetLayerCount(); + string GetLayerName(int layerIndex); + int GetLayerIndex(string layerName); + float GetLayerWeight(int layerIndex); + void SetLayerWeight(int layerIndex, float weight); + AnimatorStateInfo GetCurrentAnimatorStateInfo(int layerIndex); + AnimatorStateInfo GetNextAnimatorStateInfo(int layerIndex); + AnimatorTransitionInfo GetAnimatorTransitionInfo(int layerIndex); + AnimatorClipInfo[] GetCurrentAnimatorClipInfo(int layerIndex); + void GetCurrentAnimatorClipInfo(int layerIndex, List clips); + void GetNextAnimatorClipInfo(int layerIndex, List clips); + int GetCurrentAnimatorClipInfoCount(int layerIndex); + int GetNextAnimatorClipInfoCount(int layerIndex); + AnimatorClipInfo[] GetNextAnimatorClipInfo(int layerIndex); + bool IsInTransition(int layerIndex); + int GetParameterCount(); + AnimatorControllerParameter GetParameter(int index); + void CrossFadeInFixedTime(string stateName, float transitionDuration); + void CrossFadeInFixedTime(string stateName, float transitionDuration, int layer); + void CrossFadeInFixedTime(string stateName, float transitionDuration, int layer, float fixedTime); + void CrossFadeInFixedTime(int stateNameHash, float transitionDuration); + void CrossFadeInFixedTime(int stateNameHash, float transitionDuration, int layer); + void CrossFadeInFixedTime(int stateNameHash, float transitionDuration, int layer, float fixedTime); + void CrossFade(string stateName, float transitionDuration); + void CrossFade(string stateName, float transitionDuration, int layer); + void CrossFade(string stateName, float transitionDuration, int layer, float normalizedTime); + void CrossFade(int stateNameHash, float transitionDuration); + void CrossFade(int stateNameHash, float transitionDuration, int layer); + void CrossFade(int stateNameHash, float transitionDuration, int layer, float normalizedTime); + void PlayInFixedTime(string stateName); + void PlayInFixedTime(string stateName, int layer); + void PlayInFixedTime(string stateName, int layer, float fixedTime); + void PlayInFixedTime(int stateNameHash); + void PlayInFixedTime(int stateNameHash, int layer); + void PlayInFixedTime(int stateNameHash, int layer, float fixedTime); + void Play(string stateName); + void Play(string stateName, int layer); + void Play(string stateName, int layer, float normalizedTime); + void Play(int stateNameHash); + void Play(int stateNameHash, int layer); + void Play(int stateNameHash, int layer, float normalizedTime); + bool HasState(int layerIndex, int stateID); +} \ No newline at end of file diff --git a/KFAttached/Animation/MonoBehaviours/IAnimatorWrapper.cs.meta b/KFAttached/Animation/MonoBehaviours/IAnimatorWrapper.cs.meta new file mode 100644 index 0000000..971660e --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/IAnimatorWrapper.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b52da8de87636d42aa5130c88c5fe4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/IPlayableGraphRelated.cs b/KFAttached/Animation/MonoBehaviours/IPlayableGraphRelated.cs new file mode 100644 index 0000000..59496b8 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/IPlayableGraphRelated.cs @@ -0,0 +1,7 @@ +using UnityEngine; + +public interface IPlayableGraphRelated +{ + MonoBehaviour Init(Transform playerAnimatorTrans, bool isLocalPlayer); + void Disable(Transform playerAnimatorTrans); +} \ No newline at end of file diff --git a/KFAttached/Animation/MonoBehaviours/IPlayableGraphRelated.cs.meta b/KFAttached/Animation/MonoBehaviours/IPlayableGraphRelated.cs.meta new file mode 100644 index 0000000..9f38484 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/IPlayableGraphRelated.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 952699e2d9986c94bb12291f3d5e948a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/MonoBehaviours/RigWeightOverTime.cs b/KFAttached/Animation/MonoBehaviours/RigWeightOverTime.cs new file mode 100644 index 0000000..59b256f --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/RigWeightOverTime.cs @@ -0,0 +1,123 @@ +using System; +using System.Collections; +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("KFAttachments/Utils/Rig Weight Over Time")] +public class RigWeightOverTime : MonoBehaviour +{ + //[SerializeField] + //private Transform source; + //[SerializeField] + //private Transform target; + [SerializeReference] + private Rig[] rigs; + //[SerializeField] + //private float distanceThreshold; + //[SerializeField] + //private float distanceMax; + //private float distanceRange; + + private (Coroutine co, bool active) copair; + ////[SerializeField] + ////private bool logDistance = false; + + //private void Awake() + //{ + // distanceRange = distanceMax - distanceThreshold; + // if (distanceRange == 0) + // { + // throw new DivideByZeroException("Max distance is equal to threshold distance!"); + // } + //} + + public void OnEnable() + { + if (rigs != null) + { + SetWeight(1); + } + } + + public void OnDisable() + { + if (copair.co != null) + { + StopCoroutine(copair.co); + } + SetWeight(0); + } + + public void SetRigWeight(AnimationEvent ev) + { + if (copair.co != null) + { + StopCoroutine(copair.co); + } + bool active = Convert.ToBoolean(ev.intParameter); + copair = (StartCoroutine(UpdateWeight(ev.floatParameter, active)), active); + } + + private IEnumerator UpdateWeight(float time, bool active) + { + if (rigs == null) + { + yield break; + } + + if (time == 0) + { + SetWeight(active ? 1 : 0); + yield break; + } + + float curTime = 0; + while (curTime < time) + { + float ratio = curTime / time; + float weight = Mathf.Lerp(0, 1, active ? ratio : (1 - ratio)); + SetWeight(weight); + curTime += Time.deltaTime; + Log.Out("Set weight: " + weight); + yield return null; + } + SetWeight(active ? 1 : 0); + } + + public void SetWeight(float weight) + { + foreach (var rig in rigs) + { + rig.weight = weight; + } + } + + // private void Update() + // { + // StartCoroutine(UpdateWeight()); + // } + + // private IEnumerator UpdateWeight() + // { + // if(distanceRange == 0 || rigs == null) + // { + // yield break; + // } + // yield return new WaitForEndOfFrame(); + // float distance = Vector3.Distance(source.position, target.position); + // float weight = Mathf.Lerp(0, 1, (distanceMax - distance) / distanceRange); + // foreach (Rig rig in rigs) + // { + // rig.weight = Mathf.Lerp(rig.weight, weight, 0.5f); + // if(weight > 0 && weight < 1) + // Log.Out("ratio: " + ((distanceMax - distance) / distanceRange).ToString() + " weight: " + weight.ToString()); + // } + + //#if UNITY_EDITOR + // if (logDistance) + // { + // Log.Out(Vector3.Distance(source.position, target.position).ToString()); + // } + //#endif + // } +} \ No newline at end of file diff --git a/KFAttached/Animation/MonoBehaviours/RigWeightOverTime.cs.meta b/KFAttached/Animation/MonoBehaviours/RigWeightOverTime.cs.meta new file mode 100644 index 0000000..1c6bb50 --- /dev/null +++ b/KFAttached/Animation/MonoBehaviours/RigWeightOverTime.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b22553f7e0b6104dac02ca4c8af2c99 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/StateMachineBehaviours.meta b/KFAttached/Animation/StateMachineBehaviours.meta new file mode 100644 index 0000000..6f38ce2 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 664ef95b745768746a23509d7b250fdd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationAimRecoilResetState.cs b/KFAttached/Animation/StateMachineBehaviours/AnimationAimRecoilResetState.cs new file mode 100644 index 0000000..04e1aff --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationAimRecoilResetState.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +public class AnimationAimRecoilResetState : StateMachineBehaviour +{ + public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + animator.GetComponent()?.Rollback(); + } + + public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + animator.GetComponent()?.Rollback(); + } +} diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationAimRecoilResetState.cs.meta b/KFAttached/Animation/StateMachineBehaviours/AnimationAimRecoilResetState.cs.meta new file mode 100644 index 0000000..683f40c --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationAimRecoilResetState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 248236ebc388e4c4d8e3f700b7444ab6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationAmmoUpdateState.cs b/KFAttached/Animation/StateMachineBehaviours/AnimationAmmoUpdateState.cs new file mode 100644 index 0000000..184fea9 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationAmmoUpdateState.cs @@ -0,0 +1,66 @@ +#if NotEditor +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; +#endif +using UnityEngine; + +public class AnimationAmmoUpdateState : StateMachineBehaviour +{ +#if NotEditor + private static int[] hash_states = new[] + { + Animator.StringToHash("ammoCount"), + Animator.StringToHash("ammoCount1"), + Animator.StringToHash("ammoCount2"), + Animator.StringToHash("ammoCount3"), + Animator.StringToHash("ammoCount4") + }; + private InventorySlotGurad slotGuard = new InventorySlotGurad(); + + public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + //var player = GameManager.Instance.World?.GetPrimaryPlayer(); + var player = animator.GetComponentInParent(); + if(slotGuard.IsValid(player)) + { + SetAmmoCountForEntity(player, slotGuard.Slot); + } + } + + public static void SetAmmoCountForEntity(EntityAlive entity, int slot) + { + if (entity) + { + var invData = entity.inventory?.slots?[slot]; + if (invData?.actionData != null) + { + var mapping = MultiActionManager.GetMappingForEntity(entity.entityId); + if (mapping != null) + { + var metaIndices = mapping.indices; + for (int i = 0; i < mapping.ModeCount; i++) + { + int metaIndex = metaIndices.GetMetaIndexForMode(i); + int meta = invData.itemValue.GetMetaByMode(i); + entity.emodel.avatarController.UpdateInt(hash_states[metaIndex], meta); + if (ConsoleCmdReloadLog.LogInfo) + { + Log.Out($"Setting ammoCount{(metaIndex > 0 ? metaIndex.ToString() : "")} to {meta}, stack trace:\n{StackTraceUtility.ExtractStackTrace()}"); + } + //animator.SetInteger(hash_states[metaIndex], meta); + } + } + else + { + entity.emodel.avatarController.UpdateInt(hash_states[0], invData.itemValue.Meta); + if (ConsoleCmdReloadLog.LogInfo) + { + Log.Out($"Setting ammoCount to {invData.itemValue.Meta}, stack trace:\n{StackTraceUtility.ExtractStackTrace()}"); + } + //animator.SetInteger(hash_states[0], entity.inventory.holdingItemItemValue.Meta); + } + } + } + } +#endif +} \ No newline at end of file diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationAmmoUpdateState.cs.meta b/KFAttached/Animation/StateMachineBehaviours/AnimationAmmoUpdateState.cs.meta new file mode 100644 index 0000000..d109c5f --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationAmmoUpdateState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 87658b6a8bedcd14e83febff2157048c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationCustomMeleeAttackState.cs b/KFAttached/Animation/StateMachineBehaviours/AnimationCustomMeleeAttackState.cs new file mode 100644 index 0000000..cd000c8 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationCustomMeleeAttackState.cs @@ -0,0 +1,266 @@ +using System.Collections; +using UnityEngine; +#if UNITY_EDITOR +using UnityEditor; +using UnityEditor.Animations; +#endif + +public class AnimationCustomMeleeAttackState : StateMachineBehaviour +#if UNITY_EDITOR + , ISerializationCallbackReceiver +#endif +{ + public float RaycastTime = 0.3f; + public float CustomGrazeCastTime = 0.3f; + public float CustomGrazeCastDuration = 0f; + public float ImpactDuration = 0.01f; + [Range(0.01f, 1f)] + public float ImpactPlaybackSpeed = 1f; + [Range(0.01f, 1f)] + public float attackDurationNormalized = 1f; + [Range(0f, 360f)] + public float SwingAngle = 0f; + [Range(-180f, 180f)] + public float SwingDegrees = 0f; + + [SerializeField] + private float ClipLength = 0f; + +#if UNITY_EDITOR + public void OnBeforeSerialize() + { + var context = AnimatorController.FindStateMachineBehaviourContext(this); + if (context != null && context.Length > 0) + { + var state = context[0].animatorObject as AnimatorState; + if (state != null) + { + var clip = state.motion as AnimationClip; + if (clip != null) + { + ClipLength = clip.length; + } + } + } + } + + public void OnAfterDeserialize() + { + } +#endif + +#if NotEditor + private readonly int AttackSpeedHash = Animator.StringToHash("MeleeAttackSpeed"); + private float calculatedRaycastTime; + private float calculatedGrazeTime; + private float calculatedGrazeDuration; + private float calculatedImpactDuration; + private float calculatedImpactPlaybackSpeed; + private bool hasFired; + private int actionIndex; + private float originalMeleeAttackSpeed; + //private bool playingImpact; + private EntityAlive entity; + private float attacksPerMinute; + private float speedMultiplierToKeep = 1f; + private InventorySlotGurad slotGurad = new InventorySlotGurad(); + + public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + //if (playingImpact) + //{ + // return; + //} + hasFired = false; + actionIndex = animator.GetWrappedInt(AvatarController.itemActionIndexHash); + entity = animator.GetComponentInParent(); + if (!slotGurad.IsValid(entity)) + { + return; + } + //Log.Out("State entered!"); + //AnimatorClipInfo[] array = animator.GetNextAnimatorClipInfo(layerIndex); + float length = ClipLength * attackDurationNormalized; + ////if (array.Length == 0) + ////{ + // var array = animator.GetCurrentAnimatorClipInfo(layerIndex); + // if (array.Length == 0) + // { + // if (float.IsInfinity(stateInfo.length)) + // { + // Log.Out($"Invalid clips!"); + // return; + // } + // length = stateInfo.length; + // } + // else + // { + // length = array[0].clip.length; + // } + ////} + ////else + ////{ + //// length = array[0].clip.length; + ////} + //length *= attackDurationNormalized; + attacksPerMinute = 60f / length; + FastTags fastTags = ((actionIndex != 1) ? ItemActionAttack.PrimaryTag : ItemActionAttack.SecondaryTag); + ItemValue holdingItemItemValue = entity.inventory.holdingItemItemValue; + ItemClass itemClass = holdingItemItemValue.ItemClass; + if (itemClass != null) + { + fastTags |= itemClass.ItemTags; + } + originalMeleeAttackSpeed = EffectManager.GetValue(PassiveEffects.AttacksPerMinute, holdingItemItemValue, attacksPerMinute, entity, null, fastTags) / 60f * length; + animator.SetWrappedFloat(AttackSpeedHash, originalMeleeAttackSpeed); + speedMultiplierToKeep = originalMeleeAttackSpeed; + ItemClass holdingItem = entity.inventory.holdingItem; + holdingItem.Properties.ParseFloat((actionIndex != 1) ? "Action0.RaycastTime" : "Action1.RaycastTime", ref RaycastTime); + float impactDuration = -1f; + holdingItem.Properties.ParseFloat((actionIndex != 1) ? "Action0.ImpactDuration" : "Action1.ImpactDuration", ref impactDuration); + if (impactDuration >= 0f) + { + ImpactDuration = impactDuration * originalMeleeAttackSpeed; + } + holdingItem.Properties.ParseFloat((actionIndex != 1) ? "Action0.ImpactPlaybackSpeed" : "Action1.ImpactPlaybackSpeed", ref ImpactPlaybackSpeed); + if (originalMeleeAttackSpeed != 0f) + { + calculatedRaycastTime = RaycastTime / originalMeleeAttackSpeed; + calculatedGrazeTime = CustomGrazeCastTime / originalMeleeAttackSpeed; + calculatedGrazeDuration = CustomGrazeCastDuration / originalMeleeAttackSpeed; + calculatedImpactDuration = ImpactDuration / originalMeleeAttackSpeed; + calculatedImpactPlaybackSpeed = ImpactPlaybackSpeed * originalMeleeAttackSpeed; + } + else + { + calculatedRaycastTime = 0.001f; + calculatedGrazeTime = 0.001f; + calculatedGrazeDuration = 0.001f; + calculatedImpactDuration = 0.001f; + calculatedImpactPlaybackSpeed = 0.001f; + } + if (ConsoleCmdReloadLog.LogInfo) + { + Log.Out($"original: raycast time {RaycastTime} impact duration {ImpactDuration} impact playback speed {ImpactPlaybackSpeed} clip length {length}/{stateInfo.length}"); + Log.Out($"calculated: raycast time {calculatedRaycastTime} impact duration {calculatedImpactDuration} impact playback speed {calculatedImpactPlaybackSpeed} speed multiplier {originalMeleeAttackSpeed}"); + } + GameManager.Instance.StartCoroutine(impactStart(animator, layerIndex, length)); + GameManager.Instance.StartCoroutine(customGrazeStart(length)); + } + + private IEnumerator impactStart(Animator animator, int layer, float length) + { + yield return new WaitForSeconds(Mathf.Max(calculatedRaycastTime, 0)); + if (!hasFired) + { + hasFired = true; + if (entity != null && !entity.isEntityRemote && actionIndex >= 0) + { + ItemActionDynamicMelee.ItemActionDynamicMeleeData itemActionDynamicMeleeData = entity.inventory.holdingItemData.actionData[actionIndex] as ItemActionDynamicMelee.ItemActionDynamicMeleeData; + if (itemActionDynamicMeleeData != null) + { + if ((entity.inventory.holdingItem.Actions[actionIndex] as ItemActionDynamicMelee).Raycast(itemActionDynamicMeleeData)) + { + GameManager.Instance.StartCoroutine(impactStop(animator, layer, length)); + } + } + } + } + yield break; + } + + private IEnumerator impactStop(Animator animator, int layer, float length) + { + //playingImpact = true; + //animator.Play(0, layer, Mathf.Min(1f, calculatedRaycastTime * attackDurationNormalized / length)); + if (animator) + { + //Log.Out("Impact start!"); + animator.SetWrappedFloat(AttackSpeedHash, calculatedImpactPlaybackSpeed); + } + speedMultiplierToKeep = calculatedImpactPlaybackSpeed; + yield return new WaitForSeconds(calculatedImpactDuration); + if (animator) + { + //Log.Out("Impact stop!"); + animator.SetWrappedFloat(AttackSpeedHash, originalMeleeAttackSpeed); + } + speedMultiplierToKeep = originalMeleeAttackSpeed; + //playingImpact = false; + yield break; + } + + private IEnumerator customGrazeStart(float length) + { + if (ConsoleCmdReloadLog.LogInfo) + { + Log.Out($"Custom graze time: {calculatedGrazeTime} original {CustomGrazeCastTime}"); + } + yield return new WaitForSeconds(calculatedGrazeTime); + if (entity != null && !entity.isEntityRemote && actionIndex >= 0) + { + ItemActionDynamicMelee.ItemActionDynamicMeleeData itemActionDynamicMeleeData = entity.inventory.holdingItemData.actionData[actionIndex] as ItemActionDynamicMelee.ItemActionDynamicMeleeData; + if (itemActionDynamicMeleeData != null) + { + GameManager.Instance.StartCoroutine(customGrazeUpdate(itemActionDynamicMeleeData)); + } + } + } + + private IEnumerator customGrazeUpdate(ItemActionDynamicMelee.ItemActionDynamicMeleeData data) + { + if (ConsoleCmdReloadLog.LogInfo) + { + Log.Out($"Custom graze duration: {calculatedGrazeDuration} original {CustomGrazeCastDuration}"); + } + if (calculatedGrazeDuration <= 0f) + { + yield break; + } + float grazeStart = Time.time; + float normalizedTime = 0f; + var action = entity.inventory.holdingItem.Actions[actionIndex] as ItemActionDynamicMelee; + while (normalizedTime <= 1) + { + if (!slotGurad.IsValid(data.invData.holdingEntity)) + { + Log.Out($"Invalid graze!"); + yield break; + } + float originalSwingAngle = action.SwingAngle; + float originalSwingDegrees = action.SwingDegrees; + action.SwingAngle = SwingAngle; + action.SwingDegrees = SwingDegrees; + bool grazeResult = action.GrazeCast(data, normalizedTime); + if (ConsoleCmdReloadLog.LogInfo) + { + Log.Out($"GrazeCast {grazeResult}!"); + } + action.SwingAngle = originalSwingAngle; + action.SwingDegrees = originalSwingDegrees; + yield return null; + normalizedTime = (Time.time - grazeStart) / calculatedGrazeDuration; + } + yield break; + } + + public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + //if (entity != null && !entity.isEntityRemote && actionIndex >= 0 && entity.inventory.holdingItemData.actionData[actionIndex] is ItemActionDynamicMelee.ItemActionDynamicMeleeData) + //{ + // animator.SetFloat(AttackSpeedHash, originalMeleeAttackSpeed); + //} + animator.SetWrappedFloat(AttackSpeedHash, originalMeleeAttackSpeed); + } + + public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + //float normalizedTime = stateInfo.normalizedTime; + //if (float.IsInfinity(normalizedTime) || float.IsNaN(normalizedTime)) + //{ + // animator.Play(animator.GetNextAnimatorStateInfo(layerIndex).shortNameHash, layerIndex); + //} + animator.SetWrappedFloat(AttackSpeedHash, speedMultiplierToKeep); + } +#endif +} \ No newline at end of file diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationCustomMeleeAttackState.cs.meta b/KFAttached/Animation/StateMachineBehaviours/AnimationCustomMeleeAttackState.cs.meta new file mode 100644 index 0000000..05aad62 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationCustomMeleeAttackState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fef84a89943f52c418487a560eb789c3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationCustomReloadState.cs b/KFAttached/Animation/StateMachineBehaviours/AnimationCustomReloadState.cs new file mode 100644 index 0000000..393d996 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationCustomReloadState.cs @@ -0,0 +1,94 @@ +#if NotEditor +using KFCommonUtilityLib.Scripts.StaticManagers; +#endif +using UnityEngine; + +public class AnimationCustomReloadState : StateMachineBehaviour +{ + [SerializeField] + private float ForceCancelReloadDelay = 1f; + [SerializeField] + private bool DoNotForceCancel = false; + + public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + animator.speed = 1f; + animator.SetWrappedBool(Animator.StringToHash("Reload"), false); + animator.SetWrappedBool(Animator.StringToHash("IsReloading"), true); +#if NotEditor + if (player == null) + { + player = animator.GetComponentInParent(); + } + int actionIndex = MultiActionManager.GetActionIndexForEntity(player); +#if DEBUG + Log.Out($"start reload {actionIndex}"); +#endif + actionData = player.inventory.holdingItemData.actionData[actionIndex] as ItemActionRanged.ItemActionDataRanged; + if (eventBridge == null) + { + eventBridge = animator.GetComponent(); + } + +#if DEBUG + Log.Out($"ANIMATOR STATE ENTER : {actionData.invData.item.Name}"); +#endif + eventBridge.OnReloadStart(actionIndex); + //eventBridge.OnReloadUpdate(); +#endif + } + + public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + animator.speed = 1f; +#if NotEditor + //eventBridge.OnReloadUpdate(); + if (actionData == null) + { + return; + } + if (actionData.isReloading) + { + eventBridge.OnReloadFinish(); + } +#endif + //actionData.isReloading = false; + //actionData.isReloadCancelled = false; + //actionData.isChangingAmmoType = false; +#if DEBUG && NotEditor + Log.Out($"ANIMATOR STATE EXIT : {actionData.invData.item.Name}"); +#endif + } + +#if NotEditor + public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + //eventBridge.OnReloadUpdate(); + if (actionData == null) + { + return; + } + if (actionData.isReloadCancelled) + { + animator.speed = 30f; + + if (!DoNotForceCancel) + { + eventBridge.DelayForceCancelReload(ForceCancelReloadDelay); + } +#if DEBUG + Log.Out($"ANIMATOR UPDATE: RELOAD CANCELLED, ANIMATOR SPEED {animator.speed}"); +#endif + } + if (!actionData.isReloadCancelled && actionData.isReloading) + { + actionData.invData.holdingEntity.MinEventContext.ItemActionData = actionData; + actionData.invData.holdingEntity.FireEvent(MinEventTypes.onReloadUpdate, true); + } + } + + private ItemActionRanged.ItemActionDataRanged actionData; + private EntityAlive player; + private AnimationReloadEvents eventBridge; +#endif +} \ No newline at end of file diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationCustomReloadState.cs.meta b/KFAttached/Animation/StateMachineBehaviours/AnimationCustomReloadState.cs.meta new file mode 100644 index 0000000..b347794 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationCustomReloadState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f156c87129f85044a3336ade4d1af2c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationInspectFix.cs b/KFAttached/Animation/StateMachineBehaviours/AnimationInspectFix.cs new file mode 100644 index 0000000..a8da630 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationInspectFix.cs @@ -0,0 +1,71 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using UnityEngine.Animations.Rigging; + +public class AnimationInspectFix : MonoBehaviour, IPlayableGraphRelated +{ + [SerializeField] + private string inspectName = "Inspect"; + [SerializeField] + private int layer = 0; + [SerializeField, Range(0, 1)] + private float finishTime = 1; + [SerializeField] + private bool useStateTag = false; + private static int inspectHash = Animator.StringToHash("weaponInspect"); + private IAnimatorWrapper wrapper; + + private void Awake() + { + } + + private void Update() + { + if (wrapper == null || !wrapper.IsValid) + { + var animator = GetComponent(); + if (!animator) + { + Destroy(this); + return; + } + wrapper = animator.GetItemAnimatorWrapper(); + } + if (useStateTag) + { + var stateInfo = wrapper.GetCurrentAnimatorStateInfo(layer); + if (stateInfo.IsTag(inspectName) && stateInfo.normalizedTime < finishTime) + { + wrapper.ResetTrigger(inspectHash); + } + } + else + { + var transInfo = wrapper.GetAnimatorTransitionInfo(layer); + if (transInfo.IsUserName(inspectName) && transInfo.normalizedTime < finishTime) + { + wrapper.ResetTrigger(inspectHash); + } + } + } + + public MonoBehaviour Init(Transform playerAnimatorTrans, bool isLocalPlayer) + { + enabled = false; + var copy = isLocalPlayer ? playerAnimatorTrans.AddMissingComponent() : null; + if (copy) + { + copy.enabled = true; + } + return copy; + } + + public void Disable(Transform playerAnimatorTrans) + { + enabled = false; + } +} \ No newline at end of file diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationInspectFix.cs.meta b/KFAttached/Animation/StateMachineBehaviours/AnimationInspectFix.cs.meta new file mode 100644 index 0000000..a6f7481 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationInspectFix.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 26c7436085cc1924a882f62d81f262a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationLockAction.cs b/KFAttached/Animation/StateMachineBehaviours/AnimationLockAction.cs new file mode 100644 index 0000000..0be35dc --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationLockAction.cs @@ -0,0 +1,41 @@ +#if NotEditor +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.StaticManagers; +#endif +using UnityEngine; + +public class AnimationLockAction : StateMachineBehaviour +{ + public bool lockReload = false; +#if NotEditor + private InventorySlotGurad slotGuard = new InventorySlotGurad(); + public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + var player = animator.GetComponentInParent(); + if (slotGuard.IsValid(player)) + { + if (player.inventory.holdingItemData.actionData[MultiActionManager.GetActionIndexForEntity(player)] is IModuleContainerFor lockData) + { + lockData.Instance.isLocked = true; + if (lockReload) + { + lockData.Instance.isReloadLocked = true; + } + } + } + } + + public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + var player = animator.GetComponentInParent(); + if (slotGuard.IsValid(player)) + { + if (player.inventory.holdingItemData.actionData[MultiActionManager.GetActionIndexForEntity(player)] is IModuleContainerFor lockData) + { + lockData.Instance.isLocked = false; + lockData.Instance.isReloadLocked = false; + } + } + } +#endif +} diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationLockAction.cs.meta b/KFAttached/Animation/StateMachineBehaviours/AnimationLockAction.cs.meta new file mode 100644 index 0000000..7d68de6 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationLockAction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 41af3d052f5a46a4c86c3ffbaf4c7918 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationMultiStageReloadState.cs b/KFAttached/Animation/StateMachineBehaviours/AnimationMultiStageReloadState.cs new file mode 100644 index 0000000..073810a --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationMultiStageReloadState.cs @@ -0,0 +1,85 @@ +#if NotEditor +using KFCommonUtilityLib.Scripts.StaticManagers; +using UAI; + +#endif +using UnityEngine; + +public class AnimationMultiStageReloadState : StateMachineBehaviour +{ + [SerializeField] + private bool speedUpOnCancel; + [SerializeField] + private bool immediateCancel; + [SerializeField] + private float ForceCancelReloadDelay = 1f; + [SerializeField] + private bool DoNotForceCancel = false; + + private AnimationReloadEvents eventBridge; + + public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + animator.SetWrappedBool(Animator.StringToHash("Reload"), false); + if (eventBridge == null) + { + eventBridge = animator.GetComponent(); + } + if (stateInfo.IsTag("ReloadStart")) + { + animator.speed = 1f; + animator.SetWrappedBool(Animator.StringToHash("IsReloading"), true); +#if NotEditor + EntityAlive player = animator.GetComponentInParent(); + int actionIndex = MultiActionManager.GetActionIndexForEntity(player); + eventBridge.OnReloadStart(actionIndex); +#if DEBUG + Log.Out($"start reload {actionIndex}"); +#endif +#endif + } + } + +#if NotEditor + public override void OnStateUpdate(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + var actionData = eventBridge.actionData; + if (actionData == null) + { + return; + } + + if (actionData.isReloadCancelled) + { + if (speedUpOnCancel) + { + Log.Out("Speed up animation!"); + animator.speed = 30; + } + + if (immediateCancel) + { + animator.SetBool("IsReloading", false); + } + + if (!DoNotForceCancel) + { + eventBridge.DelayForceCancelReload(ForceCancelReloadDelay); + } + } + + if (actionData.isReloading && animator.GetBool("IsReloading")) + { + actionData.invData.holdingEntity.MinEventContext.ItemActionData = actionData; + actionData.invData.holdingEntity.FireEvent(MinEventTypes.onReloadUpdate, true); + } + } + + public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + animator.speed = 1f; + if (stateInfo.IsTag("ReloadEnd")) + eventBridge?.OnReloadFinish(); + } +#endif +} \ No newline at end of file diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationMultiStageReloadState.cs.meta b/KFAttached/Animation/StateMachineBehaviours/AnimationMultiStageReloadState.cs.meta new file mode 100644 index 0000000..508c3a1 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationMultiStageReloadState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a36e127f3f92d4f4a8c3e3fdabe6e1d6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationRandomRecoilState.cs b/KFAttached/Animation/StateMachineBehaviours/AnimationRandomRecoilState.cs new file mode 100644 index 0000000..479ae5b --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationRandomRecoilState.cs @@ -0,0 +1,12 @@ +using UnityEngine; + +public class AnimationRandomRecoilState : StateMachineBehaviour +{ + [SerializeField] private Vector3 positionMultiplier = Vector3.one; + [SerializeField] private Vector3 rotationMultiplier = Vector3.one; + + public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + animator.GetComponent()?.AddRecoil(positionMultiplier, rotationMultiplier); + } +} diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationRandomRecoilState.cs.meta b/KFAttached/Animation/StateMachineBehaviours/AnimationRandomRecoilState.cs.meta new file mode 100644 index 0000000..c6afd49 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationRandomRecoilState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a853564a7472fea44b9ba42cbf3ae654 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationResetRigWeightState.cs b/KFAttached/Animation/StateMachineBehaviours/AnimationResetRigWeightState.cs new file mode 100644 index 0000000..3000c5a --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationResetRigWeightState.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +public class AnimationResetRigWeightState : StateMachineBehaviour +{ + public override void OnStateExit(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + animator.GetComponent()?.SetWeight(0); + } +} diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationResetRigWeightState.cs.meta b/KFAttached/Animation/StateMachineBehaviours/AnimationResetRigWeightState.cs.meta new file mode 100644 index 0000000..9125b5d --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationResetRigWeightState.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9cfcbf05cdb32514bab41d81a761cd4d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationRigLayerController.cs b/KFAttached/Animation/StateMachineBehaviours/AnimationRigLayerController.cs new file mode 100644 index 0000000..fea881f --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationRigLayerController.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using UnityEngine.Animations; +using UnityEngine.Animations.Rigging; + +public class AnimationRigLayerController : StateMachineBehaviour, ISerializationCallbackReceiver +{ +#if UNITY_EDITOR + [Serializable] + public struct State + { + public byte layer; + public bool enable; + } + [SerializeField] + public State[] layerStatesEditor; +#endif + [SerializeField, HideInInspector] + private int[] layers; + + public void OnAfterDeserialize() + { + + } + + public void OnBeforeSerialize() + { +#if UNITY_EDITOR + if(layerStatesEditor != null) + { + layers = new int[layerStatesEditor.Length]; + for (int i = 0; i < layerStatesEditor.Length; i++) + { + layers[i] = layerStatesEditor[i].layer | (layerStatesEditor[i].enable ? 0 : 0x8000); + } + } +#endif + } + + public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + if (layers == null) + return; + + RigBuilder rigBuilder = animator.GetComponent(); + if (rigBuilder && rigBuilder.layers != null) + { + foreach (var layer in layers) + { + int realLayer = layer & 0x7fff; + if (realLayer >= rigBuilder.layers.Count) + { + continue; + } + rigBuilder.layers[realLayer].active = (layer & 0x8000) <= 0; + } + } + } +} \ No newline at end of file diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimationRigLayerController.cs.meta b/KFAttached/Animation/StateMachineBehaviours/AnimationRigLayerController.cs.meta new file mode 100644 index 0000000..e3e3ac5 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimationRigLayerController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dbb26fa6f1fef8f45b8eaf5702207898 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimatorRandomSwitch.cs b/KFAttached/Animation/StateMachineBehaviours/AnimatorRandomSwitch.cs new file mode 100644 index 0000000..04809b6 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimatorRandomSwitch.cs @@ -0,0 +1,45 @@ +using UnityEngine; + +[AddComponentMenu("KFAttachments/Utils/Animator Random Switch")] +public class AnimatorRandomSwitch : StateMachineBehaviour +{ + [SerializeField] + private string parameter; + [SerializeField] + private int stateCount; + + private int[] stateHits; + int totalHits; + + private void Awake() + { + stateHits = new int[stateCount]; + for (int i = 0; i < stateCount; i++) + { + stateHits[i] = 1; + } + totalHits = stateCount; + } + + public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex) + { + int rand = Random.Range(0, totalHits); + int cur = 0; + bool found = false; + for (int i = 0; i < stateHits.Length; i++) + { + cur += stateHits[i]; + if (cur > rand && !found) + { + animator.SetInteger(parameter, i); + found = true; + stateHits[i] = 1; + } + else + { + stateHits[i] = 2; + } + } + totalHits = stateCount * 2 - 1; + } +} \ No newline at end of file diff --git a/KFAttached/Animation/StateMachineBehaviours/AnimatorRandomSwitch.cs.meta b/KFAttached/Animation/StateMachineBehaviours/AnimatorRandomSwitch.cs.meta new file mode 100644 index 0000000..252d344 --- /dev/null +++ b/KFAttached/Animation/StateMachineBehaviours/AnimatorRandomSwitch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c083a728c43231842a2e50a3c04b4a11 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/FPSPack.meta b/KFAttached/FPSPack.meta new file mode 100644 index 0000000..45f332c --- /dev/null +++ b/KFAttached/FPSPack.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3e3819a4a6a281d4bbdf89ab29424071 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/FPSPack/Demo.meta b/KFAttached/FPSPack/Demo.meta new file mode 100644 index 0000000..5c9b755 --- /dev/null +++ b/KFAttached/FPSPack/Demo.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1b7fe40f86d8131479dac6a7eb9f7f66 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/FPSPack/Demo/FPSDemoGUI.cs b/KFAttached/FPSPack/Demo/FPSDemoGUI.cs new file mode 100644 index 0000000..512f247 --- /dev/null +++ b/KFAttached/FPSPack/Demo/FPSDemoGUI.cs @@ -0,0 +1,68 @@ +using UnityEngine; + +public class FPSDemoGUI : MonoBehaviour +{ + public GameObject[] Prefabs; + public Transform muzzleFlashPoint; + public GameObject Gun; + public float reactivateTime = 4; + public Light Sun; + + private int currentNomber; + private GameObject currentInstance; + private GUIStyle guiStyleHeader = new GUIStyle(); + private float sunIntensity; + float dpiScale; + + // Use this for initialization + void Start() + { + if (Screen.dpi < 1) dpiScale = 1; + if (Screen.dpi < 200) dpiScale = 1; + else dpiScale = Screen.dpi / 200f; + guiStyleHeader.fontSize = (int)(15f * dpiScale); + guiStyleHeader.normal.textColor = new Color(0.15f, 0.15f, 0.15f); + currentInstance = Instantiate(Prefabs[currentNomber], transform.position, transform.rotation) as GameObject; + var reactivator = currentInstance.AddComponent(); + reactivator.TimeDelayToReactivate = reactivateTime; + sunIntensity = Sun.intensity; + } + + private void OnGUI() + { + if (GUI.Button(new Rect(10 * dpiScale, 15 * dpiScale, 135 * dpiScale, 37 * dpiScale), "PREVIOUS EFFECT")) + { + ChangeCurrent(-1); + } + if (GUI.Button(new Rect(160 * dpiScale, 15 * dpiScale, 135 * dpiScale, 37 * dpiScale), "NEXT EFFECT")) + { + ChangeCurrent(+1); + } + sunIntensity = GUI.HorizontalSlider(new Rect(10 * dpiScale, 70 * dpiScale, 285 * dpiScale, 15 * dpiScale), sunIntensity, 0, 0.6f); + Sun.intensity = sunIntensity; + GUI.Label(new Rect(300 * dpiScale, 70 * dpiScale, 30 * dpiScale, 30 * dpiScale), "SUN INTENSITY", guiStyleHeader); + GUI.Label(new Rect(400 * dpiScale, 15 * dpiScale, 100 * dpiScale, 20 * dpiScale), "Prefab name is \"" + Prefabs[currentNomber].name + "\" \r\nHold any mouse button that would move the camera", guiStyleHeader); + } + // Update is called once per frame + void ChangeCurrent(int delta) + { + currentNomber += delta; + if (currentNomber > Prefabs.Length - 1) + currentNomber = 0; + else if (currentNomber < 0) + currentNomber = Prefabs.Length - 1; + if (currentInstance != null) Destroy(currentInstance); + if (currentNomber < 10) + { + currentInstance = Instantiate(Prefabs[currentNomber], transform.position, transform.rotation) as GameObject; + Gun.SetActive(false); + } + else + { + currentInstance = Instantiate(Prefabs[currentNomber], muzzleFlashPoint.position, muzzleFlashPoint.rotation) as GameObject; + Gun.SetActive(true); + } + var reactivator = currentInstance.AddComponent(); + reactivator.TimeDelayToReactivate = reactivateTime; + } +} diff --git a/KFAttached/FPSPack/Demo/FPSDemoGUI.cs.meta b/KFAttached/FPSPack/Demo/FPSDemoGUI.cs.meta new file mode 100644 index 0000000..2e295ea --- /dev/null +++ b/KFAttached/FPSPack/Demo/FPSDemoGUI.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f44a7ad42765c94b896425517325f1a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/FPSPack/Demo/FPSDemoReactivator.cs b/KFAttached/FPSPack/Demo/FPSDemoReactivator.cs new file mode 100644 index 0000000..486635f --- /dev/null +++ b/KFAttached/FPSPack/Demo/FPSDemoReactivator.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +public class FPSDemoReactivator : MonoBehaviour +{ + + public float StartDelay = 0; + public float TimeDelayToReactivate = 3; + + void Start() + { + InvokeRepeating("Reactivate", StartDelay, TimeDelayToReactivate); + } + + void Reactivate() + { + gameObject.SetActive(false); + gameObject.SetActive(true); + } +} diff --git a/KFAttached/FPSPack/Demo/FPSDemoReactivator.cs.meta b/KFAttached/FPSPack/Demo/FPSDemoReactivator.cs.meta new file mode 100644 index 0000000..ca4d1c1 --- /dev/null +++ b/KFAttached/FPSPack/Demo/FPSDemoReactivator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 77e369a1e74c2d84ead64ef026b1c433 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/FPSPack/Demo/FPSFireManager.cs b/KFAttached/FPSPack/Demo/FPSFireManager.cs new file mode 100644 index 0000000..dd45d1c --- /dev/null +++ b/KFAttached/FPSPack/Demo/FPSFireManager.cs @@ -0,0 +1,49 @@ +using UnityEngine; + +public class FPSFireManager : MonoBehaviour +{ + public ImpactInfo[] ImpactElemets = new ImpactInfo[0]; + public float BulletDistance = 100; + public GameObject ImpactEffect; + + void Update() + { + if (Input.GetMouseButtonDown(0)) + { + RaycastHit hit; + var ray = new Ray(transform.position, transform.forward); + if (Physics.Raycast(ray, out hit, BulletDistance)) + { + var effect = GetImpactEffect(hit.transform.gameObject); + if (effect == null) + return; + var effectIstance = Instantiate(effect, hit.point, new Quaternion()) as GameObject; + ImpactEffect.SetActive(false); + ImpactEffect.SetActive(true); + effectIstance.transform.LookAt(hit.point + hit.normal); + Destroy(effectIstance, 4); + } + + } + } + + [System.Serializable] + public class ImpactInfo + { + public MaterialType.MaterialTypeEnum MaterialType; + public GameObject ImpactEffect; + } + + GameObject GetImpactEffect(GameObject impactedGameObject) + { + var materialType = impactedGameObject.GetComponent(); + if (materialType == null) + return null; + foreach (var impactInfo in ImpactElemets) + { + if (impactInfo.MaterialType == materialType.TypeOfMaterial) + return impactInfo.ImpactEffect; + } + return null; + } +} diff --git a/KFAttached/FPSPack/Demo/FPSFireManager.cs.meta b/KFAttached/FPSPack/Demo/FPSFireManager.cs.meta new file mode 100644 index 0000000..caa05df --- /dev/null +++ b/KFAttached/FPSPack/Demo/FPSFireManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eabaea637d046b649916223ab9952a50 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/FPSPack/Demo/MouseLock.cs b/KFAttached/FPSPack/Demo/MouseLock.cs new file mode 100644 index 0000000..868c2be --- /dev/null +++ b/KFAttached/FPSPack/Demo/MouseLock.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +public class MouseLock : MonoBehaviour +{ + + // Use this for initialization + void Start() + { + + } + + // Update is called once per frame + void Update() + { +#if UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 + Screen.lockCursor = true; +#else + Cursor.visible = false; +#endif + + } +} diff --git a/KFAttached/FPSPack/Demo/MouseLock.cs.meta b/KFAttached/FPSPack/Demo/MouseLock.cs.meta new file mode 100644 index 0000000..8798665 --- /dev/null +++ b/KFAttached/FPSPack/Demo/MouseLock.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fc19b6a3661472848bf60b7ac730c242 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/FPSPack/FPSLightCurves.cs b/KFAttached/FPSPack/FPSLightCurves.cs new file mode 100644 index 0000000..dcd8cbb --- /dev/null +++ b/KFAttached/FPSPack/FPSLightCurves.cs @@ -0,0 +1,47 @@ +using UnityEngine; + +public class FPSLightCurves : MonoBehaviour +{ + public AnimationCurve LightCurve = AnimationCurve.EaseInOut(0, 0, 1, 1); + public float GraphTimeMultiplier = 1, GraphIntensityMultiplier = 1; + + private bool canUpdate; + private bool firstUpdate; + private float startTime; + private Light lightSource; + + private void Awake() + { + lightSource = GetComponent(); + } + + private void OnEnable() + { + lightSource.intensity = LightCurve.Evaluate(0); + if (firstUpdate) + { + firstUpdate = false; + return; + } + startTime = Time.time; + canUpdate = true; + } + + private void OnDisable() + { + firstUpdate = true; + canUpdate = false; + } + + private void Update() + { + var time = Time.time - startTime; + if (canUpdate) + { + var eval = LightCurve.Evaluate(time / GraphTimeMultiplier) * GraphIntensityMultiplier; + lightSource.intensity = eval; + } + if (time >= GraphTimeMultiplier) + canUpdate = false; + } +} \ No newline at end of file diff --git a/KFAttached/FPSPack/FPSLightCurves.cs.meta b/KFAttached/FPSPack/FPSLightCurves.cs.meta new file mode 100644 index 0000000..a5ce8c0 --- /dev/null +++ b/KFAttached/FPSPack/FPSLightCurves.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 22b1c2a9f789e3e47a7c58fa60e17e5d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/FPSPack/FPSParticleSystemScaler.cs b/KFAttached/FPSPack/FPSParticleSystemScaler.cs new file mode 100644 index 0000000..9f10735 --- /dev/null +++ b/KFAttached/FPSPack/FPSParticleSystemScaler.cs @@ -0,0 +1,62 @@ +using UnityEngine; + +#if UNITY_EDITOR +using UnityEditor; +#endif + +[ExecuteInEditMode] +public class FPSParticleSystemScaler : MonoBehaviour +{ + public float particlesScale = 1.0f; + + float oldScale; + + void Start() + { + oldScale = particlesScale; + } + + void Update() + { +#if UNITY_EDITOR + if (Mathf.Abs(oldScale - particlesScale) > 0.0001f && particlesScale > 0) + { + transform.localScale = new Vector3(particlesScale, particlesScale, particlesScale); + float scale = particlesScale / oldScale; + var ps = this.GetComponentsInChildren(); + + foreach (ParticleSystem particles in ps) + { + particles.startSize *= scale; + particles.startSpeed *= scale; + particles.gravityModifier *= scale; + + SerializedObject serializedObject = new SerializedObject(particles); + serializedObject.FindProperty("ClampVelocityModule.magnitude.scalar").floatValue *= scale; + serializedObject.FindProperty("ClampVelocityModule.x.scalar").floatValue *= scale; + serializedObject.FindProperty("ClampVelocityModule.y.scalar").floatValue *= scale; + serializedObject.FindProperty("ClampVelocityModule.z.scalar").floatValue *= scale; + serializedObject.FindProperty("VelocityModule.x.scalar").floatValue *= scale; + serializedObject.FindProperty("VelocityModule.y.scalar").floatValue *= scale; + serializedObject.FindProperty("VelocityModule.z.scalar").floatValue *= scale; + serializedObject.FindProperty("ColorBySpeedModule.range").vector2Value *= scale; + serializedObject.FindProperty("RotationBySpeedModule.range").vector2Value *= scale; + serializedObject.FindProperty("ForceModule.x.scalar").floatValue *= scale; + serializedObject.FindProperty("ForceModule.y.scalar").floatValue *= scale; + serializedObject.FindProperty("ForceModule.z.scalar").floatValue *= scale; + serializedObject.FindProperty("SizeBySpeedModule.range").vector2Value *= scale; + + serializedObject.ApplyModifiedProperties(); + } + + var trails = this.GetComponentsInChildren(); + foreach (TrailRenderer trail in trails) + { + trail.startWidth *= scale; + trail.endWidth *= scale; + } + oldScale = particlesScale; + } +#endif + } +} \ No newline at end of file diff --git a/KFAttached/FPSPack/FPSParticleSystemScaler.cs.meta b/KFAttached/FPSPack/FPSParticleSystemScaler.cs.meta new file mode 100644 index 0000000..2036e77 --- /dev/null +++ b/KFAttached/FPSPack/FPSParticleSystemScaler.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c035660ec1d9fd64da7beb32f35b7437 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/FPSPack/FPSRandomRotateAngle.cs b/KFAttached/FPSPack/FPSRandomRotateAngle.cs new file mode 100644 index 0000000..6dc1556 --- /dev/null +++ b/KFAttached/FPSPack/FPSRandomRotateAngle.cs @@ -0,0 +1,29 @@ +using UnityEngine; + +public class FPSRandomRotateAngle : MonoBehaviour +{ + public bool RotateX; + public bool RotateY; + public bool RotateZ = true; + + private Transform t; + + // Use this for initialization + void Awake() + { + t = transform; + } + + // Update is called once per frame + void OnEnable() + { + var rotateVector = Vector3.zero; + if (RotateX) + rotateVector.x = Random.Range(0, 360); + if (RotateY) + rotateVector.y = Random.Range(0, 360); + if (RotateZ) + rotateVector.z = Random.Range(0, 360); + t.Rotate(rotateVector); + } +} diff --git a/KFAttached/FPSPack/FPSRandomRotateAngle.cs.meta b/KFAttached/FPSPack/FPSRandomRotateAngle.cs.meta new file mode 100644 index 0000000..efdc17c --- /dev/null +++ b/KFAttached/FPSPack/FPSRandomRotateAngle.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a7a83f50808621b43bd26cd127393a40 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/FPSPack/FPSShaderColorGradient.cs b/KFAttached/FPSPack/FPSShaderColorGradient.cs new file mode 100644 index 0000000..1b2e903 --- /dev/null +++ b/KFAttached/FPSPack/FPSShaderColorGradient.cs @@ -0,0 +1,61 @@ +using UnityEngine; + +public class FPSShaderColorGradient : MonoBehaviour +{ + public string ShaderProperty = "_TintColor"; + public int MaterialID = 0; + public Gradient Color = new Gradient(); + public float TimeMultiplier = 1; + + private bool canUpdate; + private Material matInstance; + private int propertyID; + private float startTime; + private Color oldColor; + + // Use this for initialization + private void Start() + { + var rend = GetComponent(); + if (rend != null) + { + var mats = rend.materials; + if (MaterialID >= mats.Length) + Debug.Log("ShaderColorGradient: Material ID more than shader materials count."); + matInstance = mats[MaterialID]; + } + else + { + var proj = GetComponent(); + var projMat = proj.material; + if (!projMat.name.EndsWith("(Instance)")) + matInstance = new Material(projMat) { name = projMat.name + " (Instance)" }; + else + matInstance = projMat; + proj.material = matInstance; + } + + if (!matInstance.HasProperty(ShaderProperty)) + Debug.Log("ShaderColorGradient: Shader not have \"" + ShaderProperty + "\" property"); + propertyID = Shader.PropertyToID(ShaderProperty); + oldColor = matInstance.GetColor(propertyID); + } + + private void OnEnable() + { + startTime = Time.time; + canUpdate = true; + } + + private void Update() + { + var time = Time.time - startTime; + if (canUpdate) + { + var eval = Color.Evaluate(time / TimeMultiplier); + matInstance.SetColor(propertyID, eval * oldColor); + } + if (time >= TimeMultiplier) + canUpdate = false; + } +} \ No newline at end of file diff --git a/KFAttached/FPSPack/FPSShaderColorGradient.cs.meta b/KFAttached/FPSPack/FPSShaderColorGradient.cs.meta new file mode 100644 index 0000000..87a19e1 --- /dev/null +++ b/KFAttached/FPSPack/FPSShaderColorGradient.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1f6f8e03260dedb45a05a2c5f5eea632 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/FPSPack/FPSShaderFloatCurves.cs b/KFAttached/FPSPack/FPSShaderFloatCurves.cs new file mode 100644 index 0000000..62c7aa1 --- /dev/null +++ b/KFAttached/FPSPack/FPSShaderFloatCurves.cs @@ -0,0 +1,57 @@ +using UnityEngine; + +public class FPSShaderFloatCurves : MonoBehaviour +{ + public string ShaderProperty = "_BumpAmt"; + public int MaterialID = 0; + public AnimationCurve FloatPropertyCurve = AnimationCurve.EaseInOut(0, 0, 1, 1); + public float GraphTimeMultiplier = 1, GraphScaleMultiplier = 1; + + private bool canUpdate; + private Material matInstance; + private int propertyID; + private float startTime; + + private void Start() + { + var rend = GetComponent(); + if (rend != null) + { + var mats = rend.materials; + if (MaterialID >= mats.Length) + Debug.Log("ShaderColorGradient: Material ID more than shader materials count."); + matInstance = mats[MaterialID]; + } + else + { + var proj = GetComponent(); + var projMat = proj.material; + if (!projMat.name.EndsWith("(Instance)")) + matInstance = new Material(projMat) { name = projMat.name + " (Instance)" }; + else + matInstance = projMat; + proj.material = matInstance; + } + if (!matInstance.HasProperty(ShaderProperty)) + Debug.Log("ShaderColorGradient: Shader not have \"" + ShaderProperty + "\" property"); + propertyID = Shader.PropertyToID(ShaderProperty); + } + + private void OnEnable() + { + startTime = Time.time; + canUpdate = true; + } + + private void Update() + { + var time = Time.time - startTime; + if (canUpdate) + { + var eval = FloatPropertyCurve.Evaluate(time / GraphTimeMultiplier) * GraphScaleMultiplier; + matInstance.SetFloat(propertyID, eval); + } + if (time >= GraphTimeMultiplier) + canUpdate = false; + } +} \ No newline at end of file diff --git a/KFAttached/FPSPack/FPSShaderFloatCurves.cs.meta b/KFAttached/FPSPack/FPSShaderFloatCurves.cs.meta new file mode 100644 index 0000000..f66aa89 --- /dev/null +++ b/KFAttached/FPSPack/FPSShaderFloatCurves.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 91b9007bb8bdfdc4cb4e31998935a777 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/FPSPack/MaterialType.cs b/KFAttached/FPSPack/MaterialType.cs new file mode 100644 index 0000000..5ade33c --- /dev/null +++ b/KFAttached/FPSPack/MaterialType.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +public class MaterialType : MonoBehaviour +{ + + public MaterialTypeEnum TypeOfMaterial = MaterialTypeEnum.Plaster; + + [System.Serializable] + public enum MaterialTypeEnum + { + Plaster, + Metall, + Folliage, + Rock, + Wood, + Brick, + Concrete, + Dirt, + Glass, + Water + } +} diff --git a/KFAttached/FPSPack/MaterialType.cs.meta b/KFAttached/FPSPack/MaterialType.cs.meta new file mode 100644 index 0000000..3790b3d --- /dev/null +++ b/KFAttached/FPSPack/MaterialType.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e86c216f014d903439060cd429cb53a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/GG Camera Shake.meta b/KFAttached/GG Camera Shake.meta new file mode 100644 index 0000000..efb3463 --- /dev/null +++ b/KFAttached/GG Camera Shake.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d1bfb6a4682934f44be265da6de48898 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/GG Camera Shake/Runtime.meta b/KFAttached/GG Camera Shake/Runtime.meta new file mode 100644 index 0000000..f67faf5 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 721197a8e82a4304097f3e0991293e4e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/GG Camera Shake/Runtime/Attenuator.cs b/KFAttached/GG Camera Shake/Runtime/Attenuator.cs new file mode 100644 index 0000000..7164a34 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/Attenuator.cs @@ -0,0 +1,66 @@ +using UnityEngine; + +namespace CameraShake +{ + /// + /// Contains methods for changing strength and direction of shakes depending on their position. + /// + public static class Attenuator + { + /// + /// Returns multiplier for the strength of a shake, based on source and camera positions. + /// + public static float Strength(StrengthAttenuationParams pars, Vector3 sourcePosition, Vector3 cameraPosition) + { + Vector3 vec = cameraPosition - sourcePosition; + float distance = Vector3.Scale(pars.axesMultiplier, vec).magnitude; + float strength = Mathf.Clamp01(1 - (distance - pars.clippingDistance) / pars.falloffScale); + + return Power.Evaluate(strength, pars.falloffDegree); + } + + /// + /// Returns displacement, opposite to the direction to the source in camera's local space. + /// + public static Displacement Direction(Vector3 sourcePosition, Vector3 cameraPosition, Quaternion cameraRotation) + { + Displacement direction = Displacement.Zero; + direction.position = (cameraPosition - sourcePosition).normalized; + direction.position = Quaternion.Inverse(cameraRotation) * direction.position; + + direction.eulerAngles.x = direction.position.z; + direction.eulerAngles.y = direction.position.x; + direction.eulerAngles.z = -direction.position.x; + + return direction; + } + + [System.Serializable] + public class StrengthAttenuationParams + { + /// + /// Radius in which shake doesn't lose strength. + /// + [Tooltip("Radius in which shake doesn't lose strength.")] + public float clippingDistance = 10; + + /// + /// Defines how fast strength falls with distance. + /// + [Tooltip("How fast strength falls with distance.")] + public float falloffScale = 50; + + /// + /// Power of the falloff function. + /// + [Tooltip("Power of the falloff function.")] + public Degree falloffDegree = Degree.Quadratic; + + /// + /// Contribution of each axis to distance. E. g. (1, 1, 0) for a 2D game in XY plane. + /// + [Tooltip("Contribution of each axis to distance. E. g. (1, 1, 0) for a 2D game in XY plane.")] + public Vector3 axesMultiplier = Vector3.one; + } + } +} diff --git a/KFAttached/GG Camera Shake/Runtime/Attenuator.cs.meta b/KFAttached/GG Camera Shake/Runtime/Attenuator.cs.meta new file mode 100644 index 0000000..54db59f --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/Attenuator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 07aa6a8400d46274f9cbc5f3714e6a9b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/GG Camera Shake/Runtime/BounceShake.cs b/KFAttached/GG Camera Shake/Runtime/BounceShake.cs new file mode 100644 index 0000000..55e08ba --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/BounceShake.cs @@ -0,0 +1,133 @@ +using UnityEngine; + +namespace CameraShake +{ + public class BounceShake : ICameraShake + { + readonly Params pars; + readonly AnimationCurve moveCurve = AnimationCurve.EaseInOut(0, 0, 1, 1); + readonly Vector3? sourcePosition = null; + + float attenuation = 1; + Displacement direction; + Displacement previousWaypoint; + Displacement currentWaypoint; + int bounceIndex; + float t; + + /// + /// Creates an instance of BounceShake. + /// + /// Parameters of the shake. + /// World position of the source of the shake. + public BounceShake(Params parameters, Vector3? sourcePosition = null) + { + this.sourcePosition = sourcePosition; + pars = parameters; + Displacement rnd = Displacement.InsideUnitSpheres(); + direction = Displacement.Scale(rnd, pars.axesMultiplier).Normalized; + } + + /// + /// Creates an instance of BounceShake. + /// + /// Parameters of the shake. + /// Initial direction of the shake motion. + /// World position of the source of the shake. + public BounceShake(Params parameters, Displacement initialDirection, Vector3? sourcePosition = null) + { + this.sourcePosition = sourcePosition; + pars = parameters; + direction = Displacement.Scale(initialDirection, pars.axesMultiplier).Normalized; + } + + public Displacement CurrentDisplacement { get; private set; } + public bool IsFinished { get; private set; } + public void Initialize(Vector3 cameraPosition, Quaternion cameraRotation) + { + attenuation = sourcePosition == null ? + 1 : Attenuator.Strength(pars.attenuation, sourcePosition.Value, cameraPosition); + currentWaypoint = attenuation * direction.ScaledBy(pars.positionStrength, pars.rotationStrength); + } + + public void Update(float deltaTime, Vector3 cameraPosition, Quaternion cameraRotation) + { + if (t < 1) + { + + t += deltaTime * pars.freq; + if (pars.freq == 0) t = 1; + + CurrentDisplacement = Displacement.Lerp(previousWaypoint, currentWaypoint, + moveCurve.Evaluate(t)); + } + else + { + t = 0; + CurrentDisplacement = currentWaypoint; + previousWaypoint = currentWaypoint; + bounceIndex++; + if (bounceIndex > pars.numBounces) + { + IsFinished = true; + return; + } + + Displacement rnd = Displacement.InsideUnitSpheres(); + direction = -direction + + pars.randomness * Displacement.Scale(rnd, pars.axesMultiplier).Normalized; + direction = direction.Normalized; + float decayValue = 1 - (float)bounceIndex / pars.numBounces; + currentWaypoint = decayValue * decayValue * attenuation + * direction.ScaledBy(pars.positionStrength, pars.rotationStrength); + } + } + + [System.Serializable] + public class Params + { + /// + /// Strength of the shake for positional axes. + /// + [Tooltip("Strength of the shake for positional axes.")] + public float positionStrength = 0.05f; + + /// + /// Strength of the shake for rotational axes. + /// + [Tooltip("Strength of the shake for rotational axes.")] + public float rotationStrength = 0.1f; + + /// + /// Preferred direction of shaking. + /// + [Tooltip("Preferred direction of shaking.")] + public Displacement axesMultiplier = new Displacement(Vector2.one, Vector3.forward); + + /// + /// Frequency of shaking. + /// + [Tooltip("Frequency of shaking.")] + public float freq = 25; + + /// + /// Number of vibrations before stop. + /// + [Tooltip("Number of vibrations before stop.")] + public int numBounces = 5; + + /// + /// Randomness of motion. + /// + [Range(0, 1)] + [Tooltip("Randomness of motion.")] + public float randomness = 0.5f; + + /// + /// How strength falls with distance from the shake source. + /// + [Tooltip("How strength falls with distance from the shake source.")] + public Attenuator.StrengthAttenuationParams attenuation; + } + } +} diff --git a/KFAttached/GG Camera Shake/Runtime/BounceShake.cs.meta b/KFAttached/GG Camera Shake/Runtime/BounceShake.cs.meta new file mode 100644 index 0000000..786925b --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/BounceShake.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1a8a4f5340889954aa6de7013b117066 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/GG Camera Shake/Runtime/CameraShakePresets.cs b/KFAttached/GG Camera Shake/Runtime/CameraShakePresets.cs new file mode 100644 index 0000000..b5d9757 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/CameraShakePresets.cs @@ -0,0 +1,113 @@ +using UnityEngine; + +namespace CameraShake +{ + /// + /// Contains shorthands for creating common shake types. + /// + public class CameraShakePresets + { + readonly CameraShaker shaker; + + public CameraShakePresets(CameraShaker shaker) + { + this.shaker = shaker; + } + + /// + /// Suitable for short and snappy shakes in 2D. Moves camera in X and Y axes and rotates it in Z axis. + /// + /// Strength of motion in X and Y axes. + /// Strength of rotation in Z axis. + /// Frequency of shaking. + /// Number of vibrations before stop. + public void ShortShake2D( + float positionStrength = 0.08f, + float rotationStrength = 0.1f, + float freq = 25, + int numBounces = 5) + { + BounceShake.Params pars = new BounceShake.Params + { + positionStrength = positionStrength, + rotationStrength = rotationStrength, + freq = freq, + numBounces = numBounces + }; + shaker.RegisterShake(new BounceShake(pars)); + } + + /// + /// Suitable for longer and stronger shakes in 3D. Rotates camera in all three axes. + /// + /// Strength of the shake. + /// Frequency of shaking. + /// Number of vibrations before stop. + public void ShortShake3D( + float strength = 0.3f, + float freq = 25, + int numBounces = 5) + { + BounceShake.Params pars = new BounceShake.Params + { + axesMultiplier = new Displacement(Vector3.zero, new Vector3(1, 1, 0.4f)), + rotationStrength = strength, + freq = freq, + numBounces = numBounces + }; + shaker.RegisterShake(new BounceShake(pars)); + } + + /// + /// Suitable for longer and stronger shakes in 2D. Moves camera in X and Y axes and rotates it in Z axis. + /// + /// Strength of motion in X and Y axes. + /// Strength of rotation in Z axis. + /// Duration of the shake. + public void Explosion2D( + float positionStrength = 1f, + float rotationStrength = 3, + float duration = 0.5f) + { + PerlinShake.NoiseMode[] modes = + { + new PerlinShake.NoiseMode(8, 1), + new PerlinShake.NoiseMode(20, 0.3f) + }; + Envelope.EnvelopeParams envelopePars = new Envelope.EnvelopeParams(); + envelopePars.decay = duration <= 0 ? 1 : 1 / duration; + PerlinShake.Params pars = new PerlinShake.Params + { + strength = new Displacement(new Vector3(1, 1) * positionStrength, Vector3.forward * rotationStrength), + noiseModes = modes, + envelope = envelopePars, + }; + shaker.RegisterShake(new PerlinShake(pars)); + } + + /// + /// Suitable for longer and stronger shakes in 3D. Rotates camera in all three axes. + /// + /// Strength of the shake. + /// Duration of the shake. + public void Explosion3D( + float strength = 8f, + float duration = 0.7f) + { + PerlinShake.NoiseMode[] modes = + { + new PerlinShake.NoiseMode(6, 1), + new PerlinShake.NoiseMode(20, 0.2f) + }; + Envelope.EnvelopeParams envelopePars = new Envelope.EnvelopeParams(); + envelopePars.decay = duration <= 0 ? 1 : 1 / duration; + PerlinShake.Params pars = new PerlinShake.Params + { + strength = new Displacement(Vector3.zero, new Vector3(1, 1, 0.5f) * strength), + noiseModes = modes, + envelope = envelopePars, + }; + shaker.RegisterShake(new PerlinShake(pars)); + } + } +} diff --git a/KFAttached/GG Camera Shake/Runtime/CameraShakePresets.cs.meta b/KFAttached/GG Camera Shake/Runtime/CameraShakePresets.cs.meta new file mode 100644 index 0000000..41c2927 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/CameraShakePresets.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27cd455dd46fc6a47b7cc4f29f710304 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/GG Camera Shake/Runtime/CameraShaker.cs b/KFAttached/GG Camera Shake/Runtime/CameraShaker.cs new file mode 100644 index 0000000..6c3d3b1 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/CameraShaker.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace CameraShake +{ + /// + /// Camera shaker component registeres new shakes, holds a list of active shakes, and applies them to the camera additively. + /// + public class CameraShaker : MonoBehaviour + { + public static CameraShaker Instance; + public static CameraShakePresets Presets; + + readonly List activeShakes = new List(); + + [Tooltip("Transform which will be affected by the shakes.\n\nCameraShaker will set this transform's local position and rotation.")] + [SerializeField] + Transform cameraTransform; + + + [Tooltip("Scales the strength of all shakes.")] + [Range(0, 1)] + [SerializeField] + public float StrengthMultiplier = 1; + + public CameraShakePresets ShakePresets; + + + /// + /// Adds a shake to the list of active shakes. + /// + public static void Shake(ICameraShake shake) + { + if (IsInstanceNull()) return; + Instance.RegisterShake(shake); + } + + /// + /// Adds a shake to the list of active shakes. + /// + public void RegisterShake(ICameraShake shake) + { + shake.Initialize(cameraTransform.position, + cameraTransform.rotation); + activeShakes.Add(shake); + } + + /// + /// Sets the transform which will be affected by the shakes. + /// + public void SetCameraTransform(Transform cameraTransform) + { + cameraTransform.localPosition = Vector3.zero; + cameraTransform.localEulerAngles = Vector3.zero; + this.cameraTransform = cameraTransform; + } + + private void Awake() + { + Instance = this; + ShakePresets = new CameraShakePresets(this); + Presets = ShakePresets; + if (cameraTransform == null) + cameraTransform = transform; + } + + public void UpdateShake() + { + if (cameraTransform == null) return; + + Displacement cameraDisplacement = Displacement.Zero; + for (int i = activeShakes.Count - 1; i >= 0; i--) + { + if (activeShakes[i].IsFinished) + { + activeShakes.RemoveAt(i); + } + else + { + activeShakes[i].Update(Time.deltaTime, cameraTransform.position, cameraTransform.rotation); + cameraDisplacement += activeShakes[i].CurrentDisplacement; + } + } + cameraTransform.localPosition = transform.localPosition + StrengthMultiplier * cameraDisplacement.position; + cameraTransform.localRotation *= Quaternion.Euler(StrengthMultiplier * cameraDisplacement.eulerAngles); + } + + private static bool IsInstanceNull() + { + if (Instance == null) + { + Debug.LogError("CameraShaker Instance is missing!"); + return true; + } + return false; + } + } +} diff --git a/KFAttached/GG Camera Shake/Runtime/CameraShaker.cs.meta b/KFAttached/GG Camera Shake/Runtime/CameraShaker.cs.meta new file mode 100644 index 0000000..ea1fa09 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/CameraShaker.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a257897ce04dc64eb5ae266c62846be +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/GG Camera Shake/Runtime/Displacement.cs b/KFAttached/GG Camera Shake/Runtime/Displacement.cs new file mode 100644 index 0000000..5a3ff8e --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/Displacement.cs @@ -0,0 +1,98 @@ +using UnityEngine; + +namespace CameraShake +{ + /// + /// Representation of translation and rotation. + /// + [System.Serializable] + public struct Displacement + { + public Vector3 position; + public Vector3 eulerAngles; + + public Displacement(Vector3 position, Vector3 eulerAngles) + { + this.position = position; + this.eulerAngles = eulerAngles; + } + + public Displacement(Vector3 position) + { + this.position = position; + this.eulerAngles = Vector3.zero; + } + + public static Displacement Zero + { + get + { + return new Displacement(Vector3.zero, Vector3.zero); + } + } + + public static Displacement operator +(Displacement a, Displacement b) + { + return new Displacement(a.position + b.position, + b.eulerAngles + a.eulerAngles); + } + + public static Displacement operator -(Displacement a, Displacement b) + { + return new Displacement(a.position - b.position, + b.eulerAngles - a.eulerAngles); + } + + public static Displacement operator -(Displacement disp) + { + return new Displacement(-disp.position, -disp.eulerAngles); + } + + public static Displacement operator *(Displacement coords, float number) + { + return new Displacement(coords.position * number, + coords.eulerAngles * number); + } + + public static Displacement operator *(float number, Displacement coords) + { + return coords * number; + } + + public static Displacement operator /(Displacement coords, float number) + { + return new Displacement(coords.position / number, + coords.eulerAngles / number); + } + + public static Displacement Scale(Displacement a, Displacement b) + { + return new Displacement(Vector3.Scale(a.position, b.position), + Vector3.Scale(b.eulerAngles, a.eulerAngles)); + } + + public static Displacement Lerp(Displacement a, Displacement b, float t) + { + return new Displacement(Vector3.Lerp(a.position, b.position, t), + Vector3.Lerp(a.eulerAngles, b.eulerAngles, t)); + } + + public Displacement ScaledBy(float posScale, float rotScale) + { + return new Displacement(position * posScale, eulerAngles * rotScale); + } + + public Displacement Normalized + { + get + { + return new Displacement(position.normalized, eulerAngles.normalized); + } + } + + public static Displacement InsideUnitSpheres() + { + return new Displacement(Random.insideUnitSphere, Random.insideUnitSphere); + } + } +} \ No newline at end of file diff --git a/KFAttached/GG Camera Shake/Runtime/Displacement.cs.meta b/KFAttached/GG Camera Shake/Runtime/Displacement.cs.meta new file mode 100644 index 0000000..3e612a0 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/Displacement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 22dc566280f4a704d958e931abdb9fc4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/GG Camera Shake/Runtime/Envelope.cs b/KFAttached/GG Camera Shake/Runtime/Envelope.cs new file mode 100644 index 0000000..21c5a28 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/Envelope.cs @@ -0,0 +1,168 @@ +using UnityEngine; + +namespace CameraShake +{ + /// + /// Controls strength of the shake over time. + /// + public class Envelope : IAmplitudeController + { + readonly EnvelopeParams pars; + readonly EnvelopeControlMode controlMode; + + float amplitude; + float targetAmplitude; + float sustainEndTime; + bool finishWhenAmplitudeZero; + bool finishImmediately; + EnvelopeState state; + + /// + /// Creates an Envelope instance. + /// + /// Envelope parameters. + /// Pass Auto for a single shake, or Manual for controlling strength manually. + public Envelope(EnvelopeParams pars, float initialTargetAmplitude, EnvelopeControlMode controlMode) + { + this.pars = pars; + this.controlMode = controlMode; + SetTarget(initialTargetAmplitude); + } + + /// + /// The value by which you want to multiply shake displacement. + /// + public float Intensity { get; private set; } + + public bool IsFinished + { + get + { + if (finishImmediately) return true; + return (finishWhenAmplitudeZero || controlMode == EnvelopeControlMode.Auto) + && amplitude <= 0 && targetAmplitude <= 0; + } + } + + public void Finish() + { + finishWhenAmplitudeZero = true; + SetTarget(0); + } + + public void FinishImmediately() + { + finishImmediately = true; + } + + /// + /// Update is called every frame by the shake. + /// + public void Update(float deltaTime) + { + if (IsFinished) return; + + if (state == EnvelopeState.Increase) + { + if (pars.attack > 0) + amplitude += deltaTime * pars.attack; + if (amplitude > targetAmplitude || pars.attack <= 0) + { + amplitude = targetAmplitude; + state = EnvelopeState.Sustain; + if (controlMode == EnvelopeControlMode.Auto) + sustainEndTime = Time.time + pars.sustain; + } + } + else + { + if (state == EnvelopeState.Decrease) + { + + if (pars.decay > 0) + amplitude -= deltaTime * pars.decay; + if (amplitude < targetAmplitude || pars.decay <= 0) + { + amplitude = targetAmplitude; + state = EnvelopeState.Sustain; + } + } + else + { + if (controlMode == EnvelopeControlMode.Auto && Time.time > sustainEndTime) + { + SetTarget(0); + } + } + } + + amplitude = Mathf.Clamp01(amplitude); + Intensity = Power.Evaluate(amplitude, pars.degree); + } + + public void SetTargetAmplitude(float value) + { + if (controlMode == EnvelopeControlMode.Manual && !finishWhenAmplitudeZero) + { + SetTarget(value); + } + } + + private void SetTarget(float value) + { + targetAmplitude = Mathf.Clamp01(value); + state = targetAmplitude > amplitude ? EnvelopeState.Increase : EnvelopeState.Decrease; + } + + + [System.Serializable] + public class EnvelopeParams + { + /// + /// How fast the amplitude rises. + /// + [Tooltip("How fast the amplitude increases.")] + public float attack = 10; + + /// + /// How long in seconds the amplitude holds a maximum value. + /// + [Tooltip("How long in seconds the amplitude holds maximum value.")] + public float sustain = 0; + + /// + /// How fast the amplitude falls. + /// + [Tooltip("How fast the amplitude decreases.")] + public float decay = 1f; + + /// + /// Power in which the amplitude is raised to get intensity. + /// + [Tooltip("Power in which the amplitude is raised to get intensity.")] + public Degree degree = Degree.Cubic; + } + + public enum EnvelopeControlMode { Auto, Manual } + + public enum EnvelopeState { Sustain, Increase, Decrease } + } + + public interface IAmplitudeController + { + /// + /// Sets value to which amplitude will move over time. + /// + void SetTargetAmplitude(float value); + + /// + /// Sets amplitude to zero and finishes the shake when zero is reached. + /// + void Finish(); + + /// + /// Immediately finishes the shake. + /// + void FinishImmediately(); + } +} diff --git a/KFAttached/GG Camera Shake/Runtime/Envelope.cs.meta b/KFAttached/GG Camera Shake/Runtime/Envelope.cs.meta new file mode 100644 index 0000000..f7208e4 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/Envelope.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 13084b7de651ead408d3f5ef8c6837b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/GG Camera Shake/Runtime/ICameraShake.cs b/KFAttached/GG Camera Shake/Runtime/ICameraShake.cs new file mode 100644 index 0000000..ab29f2d --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/ICameraShake.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +namespace CameraShake +{ + public interface ICameraShake + { + /// + /// Represents current position and rotation of the camera according to the shake. + /// + Displacement CurrentDisplacement { get; } + + /// + /// Shake system will dispose the shake on the first frame when this is true. + /// + bool IsFinished { get; } + + /// + /// CameraShaker calls this when the shake is added to the list of active shakes. + /// + void Initialize(Vector3 cameraPosition, Quaternion cameraRotation); + + /// + /// CameraShaker calls this every frame on active shakes. + /// + void Update(float deltaTime, Vector3 cameraPosition, Quaternion cameraRotation); + } +} diff --git a/KFAttached/GG Camera Shake/Runtime/ICameraShake.cs.meta b/KFAttached/GG Camera Shake/Runtime/ICameraShake.cs.meta new file mode 100644 index 0000000..f41b72e --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/ICameraShake.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a062a4046bad80b469554a84b9b30cab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/GG Camera Shake/Runtime/KickShake.cs b/KFAttached/GG Camera Shake/Runtime/KickShake.cs new file mode 100644 index 0000000..dc56c41 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/KickShake.cs @@ -0,0 +1,121 @@ +using UnityEngine; + +namespace CameraShake +{ + public class KickShake : ICameraShake + { + readonly Params pars; + readonly Vector3? sourcePosition; + readonly bool attenuateStrength; + + Displacement direction; + Displacement prevWaypoint; + Displacement currentWaypoint; + bool release; + float t; + + /// + /// Creates an instance of KickShake in the direction from the source to the camera. + /// + /// Parameters of the shake. + /// World position of the source of the shake. + /// Change strength depending on distance from the camera? + public KickShake(Params parameters, Vector3 sourcePosition, bool attenuateStrength) + { + pars = parameters; + this.sourcePosition = sourcePosition; + this.attenuateStrength = attenuateStrength; + } + + /// + /// Creates an instance of KickShake. + /// + /// Parameters of the shake. + /// Direction of the kick. + public KickShake(Params parameters, Displacement direction) + { + pars = parameters; + this.direction = direction.Normalized; + } + + public Displacement CurrentDisplacement { get; private set; } + public bool IsFinished { get; private set; } + + + public void Initialize(Vector3 cameraPosition, Quaternion cameraRotation) + { + if (sourcePosition != null) + { + direction = Attenuator.Direction(sourcePosition.Value, cameraPosition, cameraRotation); + if (attenuateStrength) + direction *= Attenuator.Strength(pars.attenuation, sourcePosition.Value, cameraPosition); + } + currentWaypoint = Displacement.Scale(direction, pars.strength); + } + + public void Update(float deltaTime, Vector3 cameraPosition, Quaternion cameraRotation) + { + if (t < 1) + { + Move(deltaTime, + release ? pars.releaseTime : pars.attackTime, + release ? pars.releaseCurve : pars.attackCurve); + } + else + { + CurrentDisplacement = currentWaypoint; + prevWaypoint = currentWaypoint; + if (release) + { + IsFinished = true; + return; + } + else + { + release = true; + t = 0; + currentWaypoint = Displacement.Zero; + } + } + } + + private void Move(float deltaTime, float duration, AnimationCurve curve) + { + if (duration > 0) + t += deltaTime / duration; + else + t = 1; + CurrentDisplacement = Displacement.Lerp(prevWaypoint, currentWaypoint, curve.Evaluate(t)); + } + + [System.Serializable] + public class Params + { + /// + /// Strength of the shake for each axis. + /// + [Tooltip("Strength of the shake for each axis.")] + public Displacement strength = new Displacement(Vector3.zero, Vector3.one); + + /// + /// How long it takes to move forward. + /// + [Tooltip("How long it takes to move forward.")] + public float attackTime = 0.05f; + public AnimationCurve attackCurve = AnimationCurve.EaseInOut(0, 0, 1, 1); + + /// + /// How long it takes to move back. + /// + [Tooltip("How long it takes to move back.")] + public float releaseTime = 0.2f; + public AnimationCurve releaseCurve = AnimationCurve.EaseInOut(0, 0, 1, 1); + + /// + /// How strength falls with distance from the shake source. + /// + [Tooltip("How strength falls with distance from the shake source.")] + public Attenuator.StrengthAttenuationParams attenuation; + } + } +} diff --git a/KFAttached/GG Camera Shake/Runtime/KickShake.cs.meta b/KFAttached/GG Camera Shake/Runtime/KickShake.cs.meta new file mode 100644 index 0000000..9f084d9 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/KickShake.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aacae9308ca14a04a8174bd35d85a1be +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/GG Camera Shake/Runtime/PerlinShake.cs b/KFAttached/GG Camera Shake/Runtime/PerlinShake.cs new file mode 100644 index 0000000..9e254b2 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/PerlinShake.cs @@ -0,0 +1,144 @@ +using UnityEngine; + +namespace CameraShake +{ + public class PerlinShake : ICameraShake + { + readonly Params pars; + readonly Envelope envelope; + + public IAmplitudeController AmplitudeController; + + Vector2[] seeds; + float time; + Vector3? sourcePosition; + float norm; + + /// + /// Creates an instance of PerlinShake. + /// + /// Parameters of the shake. + /// Maximum amplitude of the shake. + /// World position of the source of the shake. + /// Pass true if you want to control amplitude manually. + public PerlinShake( + Params parameters, + float maxAmplitude = 1, + Vector3? sourcePosition = null, + bool manualStrengthControl = false) + { + pars = parameters; + envelope = new Envelope(pars.envelope, maxAmplitude, + manualStrengthControl ? + Envelope.EnvelopeControlMode.Manual : Envelope.EnvelopeControlMode.Auto); + AmplitudeController = envelope; + this.sourcePosition = sourcePosition; + } + + public Displacement CurrentDisplacement { get; private set; } + public bool IsFinished { get; private set; } + + public void Initialize(Vector3 cameraPosition, Quaternion cameraRotation) + { + seeds = new Vector2[pars.noiseModes.Length]; + norm = 0; + for (int i = 0; i < seeds.Length; i++) + { + seeds[i] = Random.insideUnitCircle * 20; + norm += pars.noiseModes[i].amplitude; + } + } + + public void Update(float deltaTime, Vector3 cameraPosition, Quaternion cameraRotation) + { + if (envelope.IsFinished) + { + IsFinished = true; + return; + } + time += deltaTime; + envelope.Update(deltaTime); + + Displacement disp = Displacement.Zero; + for (int i = 0; i < pars.noiseModes.Length; i++) + { + disp += pars.noiseModes[i].amplitude / norm * + SampleNoise(seeds[i], pars.noiseModes[i].freq); + } + + CurrentDisplacement = envelope.Intensity * Displacement.Scale(disp, pars.strength); + if (sourcePosition != null) + CurrentDisplacement *= Attenuator.Strength(pars.attenuation, sourcePosition.Value, cameraPosition); + } + + private Displacement SampleNoise(Vector2 seed, float freq) + { + Vector3 position = new Vector3( + Mathf.PerlinNoise(seed.x + time * freq, seed.y), + Mathf.PerlinNoise(seed.x, seed.y + time * freq), + Mathf.PerlinNoise(seed.x + time * freq, seed.y + time * freq)); + position -= Vector3.one * 0.5f; + + Vector3 rotation = new Vector3( + Mathf.PerlinNoise(-seed.x - time * freq, -seed.y), + Mathf.PerlinNoise(-seed.x, -seed.y - time * freq), + Mathf.PerlinNoise(-seed.x - time * freq, -seed.y - time * freq)); + rotation -= Vector3.one * 0.5f; + + return new Displacement(position, rotation); + } + + + [System.Serializable] + public class Params + { + /// + /// Strength of the shake for each axis. + /// + [Tooltip("Strength of the shake for each axis.")] + public Displacement strength = new Displacement(Vector3.zero, new Vector3(2, 2, 0.8f)); + + /// + /// Layers of perlin noise with different frequencies. + /// + [Tooltip("Layers of perlin noise with different frequencies.")] + public NoiseMode[] noiseModes = { new NoiseMode(12, 1) }; + + /// + /// Strength over time. + /// + [Tooltip("Strength of the shake over time.")] + public Envelope.EnvelopeParams envelope; + + /// + /// How strength falls with distance from the shake source. + /// + [Tooltip("How strength falls with distance from the shake source.")] + public Attenuator.StrengthAttenuationParams attenuation; + } + + + [System.Serializable] + public struct NoiseMode + { + public NoiseMode(float freq, float amplitude) + { + this.freq = freq; + this.amplitude = amplitude; + } + + /// + /// Frequency multiplier for the noise. + /// + [Tooltip("Frequency multiplier for the noise.")] + public float freq; + + /// + /// Amplitude of the mode. + /// + [Tooltip("Amplitude of the mode.")] + [Range(0, 1)] + public float amplitude; + } + } +} diff --git a/KFAttached/GG Camera Shake/Runtime/PerlinShake.cs.meta b/KFAttached/GG Camera Shake/Runtime/PerlinShake.cs.meta new file mode 100644 index 0000000..d3911c2 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/PerlinShake.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: de97a9ba28783f34cae2c44c1d4446d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/GG Camera Shake/Runtime/Power.cs b/KFAttached/GG Camera Shake/Runtime/Power.cs new file mode 100644 index 0000000..9dd5864 --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/Power.cs @@ -0,0 +1,24 @@ +namespace CameraShake +{ + public static class Power + { + public static float Evaluate(float value, Degree degree) + { + switch (degree) + { + case Degree.Linear: + return value; + case Degree.Quadratic: + return value * value; + case Degree.Cubic: + return value * value * value; + case Degree.Quadric: + return value * value * value * value; + default: + return value; + } + } + } + + public enum Degree { Linear, Quadratic, Cubic, Quadric } +} diff --git a/KFAttached/GG Camera Shake/Runtime/Power.cs.meta b/KFAttached/GG Camera Shake/Runtime/Power.cs.meta new file mode 100644 index 0000000..89ea42d --- /dev/null +++ b/KFAttached/GG Camera Shake/Runtime/Power.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ae1c138ac39e5704daa47650c0a286d0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFCommonUtilityLib.asmdef b/KFAttached/KFCommonUtilityLib.asmdef new file mode 100644 index 0000000..2d0426f --- /dev/null +++ b/KFAttached/KFCommonUtilityLib.asmdef @@ -0,0 +1,20 @@ +{ + "name": "KFCommonUtilityLib", + "rootNamespace": "", + "references": [ + "GUID:7f7d1af65c2641843945d409d28f2e20", + "GUID:2665a8d13d1b3f18800f46e256720795", + "GUID:d8b63aba1907145bea998dd612889d6b", + "GUID:6055be8ebefd69e48b49212b09b47b2f", + "GUID:d60799ab2a985554ea1a39cd38695018" + ], + "includePlatforms": [], + "excludePlatforms": [], + "allowUnsafeCode": false, + "overrideReferences": false, + "precompiledReferences": [], + "autoReferenced": true, + "defineConstraints": [], + "versionDefines": [], + "noEngineReferences": false +} \ No newline at end of file diff --git a/KFAttached/KFCommonUtilityLib.asmdef.meta b/KFAttached/KFCommonUtilityLib.asmdef.meta new file mode 100644 index 0000000..e137f71 --- /dev/null +++ b/KFAttached/KFCommonUtilityLib.asmdef.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 63c0eca1c28248248af7caf2a72a6055 +AssemblyDefinitionImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached.meta b/KFAttached/KFUtilAttached.meta new file mode 100644 index 0000000..9779b0a --- /dev/null +++ b/KFAttached/KFUtilAttached.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 72825f9e8d606284ba3dd8559d6e91fc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/ApexWeaponHudControllerBase.cs b/KFAttached/KFUtilAttached/ApexWeaponHudControllerBase.cs new file mode 100644 index 0000000..5156048 --- /dev/null +++ b/KFAttached/KFUtilAttached/ApexWeaponHudControllerBase.cs @@ -0,0 +1,154 @@ +using System; +using TMPro; +using UnityEngine; + +public class ApexWeaponHudControllerBase : MonoBehaviour +{ + [SerializeField] + protected ComputeShader cptShader; + [SerializeField, Range(0, 100)] + protected int interPerc; + [SerializeField] + protected TMP_Text boundText; + [SerializeField] + protected TMP_Text[] miscText; + [SerializeField] + protected Renderer screenRenderer; + [SerializeField] + protected Texture maskTexture; + [SerializeField] + protected int matIndex; + [SerializeField, Range(0, 32)] + protected int depth = 0; + [SerializeField] + protected RenderTextureFormat renderTextureFormat = RenderTextureFormat.Default; + [SerializeField] + protected FilterMode filterMode = FilterMode.Point; + [SerializeField] + protected UnityEngine.Experimental.Rendering.GraphicsFormat graphicsFormat = UnityEngine.Experimental.Rendering.GraphicsFormat.R8G8B8A8_SRGB; + [SerializeField] + private string kernalName; + [SerializeField, Range(0, 1)] + protected float xScale = 1, yScale = 1; + protected int kernalIndex = -1; + protected Material mat; + protected int xGroupCount, yGroupCount; + protected CustomRenderTexture targetTexture; + protected static bool shaderEnabled; + protected static bool stateChecked = false; + //max count, elem count, inter pixels, map size + protected readonly int[] dataArray = new int[3]; + protected Color color = Color.white; + + protected static readonly int id_color = Shader.PropertyToID("color"); + protected static readonly int id_dataArray = Shader.PropertyToID("dataArray"); + protected static readonly int id_Mask = Shader.PropertyToID("Mask"); + protected static readonly int id_EmissionMap = Shader.PropertyToID("EmissionMap"); + protected static readonly int id_EmissionColor = Shader.PropertyToID("_EmissionColor"); + + protected virtual void Awake() + { + if (!stateChecked) + { + shaderEnabled = SystemInfo.supportsComputeShaders && SystemInfo.graphicsDeviceType != UnityEngine.Rendering.GraphicsDeviceType.Null && !Application.isBatchMode; + stateChecked = true; + Console.WriteLine("Compute shader support: " + shaderEnabled); + } + + dataArray[0] = 1; + dataArray[1] = 0; + dataArray[2] = interPerc; + xGroupCount = (int)(maskTexture.width * xScale / 8); + yGroupCount = (int)(maskTexture.height * yScale / 8); + mat = screenRenderer.materials[matIndex]; + } + + protected virtual void OnEnable() + { + if (!shaderEnabled) + return; + + if (targetTexture == null) + { + targetTexture = new CustomRenderTexture(maskTexture.width, maskTexture.height, renderTextureFormat) + { + enableRandomWrite = true, + updateMode = CustomRenderTextureUpdateMode.OnDemand, + depth = depth, + useMipMap = false, + autoGenerateMips = false, + filterMode = filterMode, + graphicsFormat = graphicsFormat, + wrapMode = TextureWrapMode.Clamp + }; + } + + if (!targetTexture.IsCreated()) + targetTexture.Create(); + + mat.SetTexture("_EmissionMap", targetTexture); + mat.SetColor(id_EmissionColor, Color.white); + mat.EnableKeyword("_EMISSION"); + if (cptShader.HasKernel(kernalName)) + kernalIndex = cptShader.FindKernel(kernalName); + } + + protected virtual void OnDisable() + { + + } + + protected virtual void OnDestroy() + { + OnDisable(); + if (targetTexture != null) + targetTexture.Release(); + } + + public virtual void SetColor(Color color) + { + if (boundText != null) + boundText.color = color; + if (miscText != null) + foreach (var t in miscText) + t.color = color; + + this.color = color; + //mat.SetColor(id_EmissionColor, color); + if (CanDispatch()) + Dispatch(dataArray); + } + + public virtual void SetText(string text) + { + if (text.StartsWith("#")) + { + dataArray[0] = Mathf.Max(int.Parse(text.Substring(1)), 1); + } + else + { + if (boundText != null) + boundText.SetText(text); + dataArray[1] = int.Parse(text); + } + + if (CanDispatch()) + Dispatch(dataArray); + } + + protected virtual bool CanDispatch() + { + return shaderEnabled && kernalIndex >= 0; + } + + protected virtual void Dispatch(int[] dataArray) + { + cptShader.SetInts(id_dataArray, dataArray); + cptShader.SetVector(id_color, color); + cptShader.SetTexture(kernalIndex, id_Mask, maskTexture); + cptShader.SetTexture(kernalIndex, id_EmissionMap, targetTexture, 0); + cptShader.Dispatch(kernalIndex, xGroupCount, yGroupCount, 1); + //targetTexture.GenerateMips(); + //targetTexture.Update(); + } +} diff --git a/KFAttached/KFUtilAttached/ApexWeaponHudControllerBase.cs.meta b/KFAttached/KFUtilAttached/ApexWeaponHudControllerBase.cs.meta new file mode 100644 index 0000000..d33b3ba --- /dev/null +++ b/KFAttached/KFUtilAttached/ApexWeaponHudControllerBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b0e18e2e55ec5014aad7a8808cd65efa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/ChargeUpController.cs b/KFAttached/KFUtilAttached/ChargeUpController.cs new file mode 100644 index 0000000..e5356a7 --- /dev/null +++ b/KFAttached/KFUtilAttached/ChargeUpController.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +[AddComponentMenu("KFAttachments/Weapon Display Controllers/Charge Up controller")] +public class ChargeUpController : MonoBehaviour +{ + [SerializeField] + private WeaponLabelControllerChargeUp controller; + private void OnEnable() + { + controller.StartChargeUp(); + } + + private void OnDisable() + { + controller.StopChargeUp(); + } +} diff --git a/KFAttached/KFUtilAttached/ChargeUpController.cs.meta b/KFAttached/KFUtilAttached/ChargeUpController.cs.meta new file mode 100644 index 0000000..4df5374 --- /dev/null +++ b/KFAttached/KFUtilAttached/ChargeUpController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ccb8b18bea7ff8843a380b9e611799de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/MuzzlePositionBinding.cs b/KFAttached/KFUtilAttached/MuzzlePositionBinding.cs new file mode 100644 index 0000000..447e379 --- /dev/null +++ b/KFAttached/KFUtilAttached/MuzzlePositionBinding.cs @@ -0,0 +1,33 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +[AddComponentMenu("Muzzle Position Binding")] +public class MuzzlePositionBinding : MonoBehaviour +{ + [SerializeField] + private Transform muzzleTrans; + [SerializeField] + private Vector3 newMuzzlePosition; + private Vector3 initialPosition; + private void Awake() + { + if (muzzleTrans) + initialPosition = transform.localPosition; + } + + private void OnEnable() + { + if (muzzleTrans) + muzzleTrans.localPosition = newMuzzlePosition; + } + + private void OnDisable() + { + if (muzzleTrans) + muzzleTrans.localPosition = initialPosition; + } +} diff --git a/KFAttached/KFUtilAttached/MuzzlePositionBinding.cs.meta b/KFAttached/KFUtilAttached/MuzzlePositionBinding.cs.meta new file mode 100644 index 0000000..9248bb9 --- /dev/null +++ b/KFAttached/KFUtilAttached/MuzzlePositionBinding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5d4b7e316af9faf4f9697b0d60f96793 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/RigActivationBinding.cs b/KFAttached/KFUtilAttached/RigActivationBinding.cs new file mode 100644 index 0000000..b2acc11 --- /dev/null +++ b/KFAttached/KFUtilAttached/RigActivationBinding.cs @@ -0,0 +1,69 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("KFAttachments/Binding Helpers/Rig Activation Binding")] +public class RigActivationBinding : MonoBehaviour +{ + [SerializeField] + private RigLayer[] bindings; + [SerializeField] + private RigLayer[] inverseBindings; + [SerializeField] + private RigLayer[] enableOnDisable; + [SerializeField] + private RigLayer[] disableOnEnable; + + private void OnEnable() + { + //Log.Out(gameObject.name + " OnEnable!"); + if (bindings != null) + { + foreach (RigLayer t in bindings) + if (t != null) + t.active = true; + } + if (inverseBindings != null) + { + foreach (RigLayer t in inverseBindings) + { + if (t != null) + t.active = false; + } + } + if (disableOnEnable != null) + { + foreach (RigLayer t in disableOnEnable) + { + if (t != null) + t.active = false; + } + } + } + + private void OnDisable() + { + //Log.Out(gameObject.name + " OnDisable!"); + if (bindings != null) + { + foreach (RigLayer t in bindings) + if (t != null) + t.active = false; + } + if (inverseBindings != null) + { + foreach (RigLayer t in inverseBindings) + { + if (t != null) + t.active = true; + } + } + if (enableOnDisable != null) + { + foreach (RigLayer t in enableOnDisable) + { + if (t != null) + t.active = true; + } + } + } +} diff --git a/KFAttached/KFUtilAttached/RigActivationBinding.cs.meta b/KFAttached/KFUtilAttached/RigActivationBinding.cs.meta new file mode 100644 index 0000000..d59db40 --- /dev/null +++ b/KFAttached/KFUtilAttached/RigActivationBinding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 01778f8886cb5864c842e544741586b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/TransformActivationBinding.cs b/KFAttached/KFUtilAttached/TransformActivationBinding.cs new file mode 100644 index 0000000..8d67275 --- /dev/null +++ b/KFAttached/KFUtilAttached/TransformActivationBinding.cs @@ -0,0 +1,141 @@ +using System.Collections; +using UnityEngine; + +[AddComponentMenu("KFAttachments/Binding Helpers/Transform Activation Binding")] +public class TransformActivationBinding : MonoBehaviour +{ + [SerializeField] + internal GameObject[] bindings; + [SerializeField] + private GameObject[] inverseBindings; + [SerializeField] + private GameObject[] enableOnDisable; + [SerializeField] + private GameObject[] disableOnEnable; + [SerializeField] + private GameObject[] enableOnEnable; + [SerializeField] + private GameObject[] disableOnDisable; + [SerializeField] + private string[] animatorParamBindings; + internal AnimationTargetsAbs targets; + + private void OnEnable() + { + //Log.Out(gameObject.name + " OnEnable!"); + if (bindings != null) + { + foreach (GameObject t in bindings) + { + if (t) + t.SetActive(true); + } + } + if (inverseBindings != null) + { + foreach (GameObject t in inverseBindings) + { + if (t) + t.SetActive(false); + } + } + if (disableOnEnable != null) + { + foreach (GameObject t in disableOnEnable) + { + if (t) + t.SetActive(false); + } + } + if (enableOnEnable != null) + { + foreach (GameObject t in enableOnEnable) + { + if (t) + t.SetActive(true); + } + } +#if NotEditor + ThreadManager.StartCoroutine(UpdateBool(true)); +#else + UpdateBoolEditor(true); +#endif + } + + private void OnDisable() + { + //Log.Out(gameObject.name + " OnDisable!"); + if (bindings != null) + { + foreach (GameObject t in bindings) + if (t) + t.SetActive(false); + } + if (inverseBindings != null) + { + foreach (GameObject t in inverseBindings) + { + if (t) + t.SetActive(true); + } + } + if (enableOnDisable != null) + { + foreach (GameObject t in enableOnDisable) + { + if (t) + t.SetActive(true); + } + } + if (disableOnDisable != null) + { + foreach (GameObject t in disableOnDisable) + { + if (t) + t.SetActive(true); + } + } +#if NotEditor + ThreadManager.StartCoroutine(UpdateBool(false)); +#else + UpdateBoolEditor(false); +#endif + } + +#if NotEditor + internal IEnumerator UpdateBool(bool enabled) + { + yield return new WaitForEndOfFrame(); + if (animatorParamBindings != null && targets && targets.IsAnimationSet) + { + foreach (string str in animatorParamBindings) + { + if (str != null) + { + targets.GraphBuilder.Player.emodel.avatarController.UpdateBool(str, enabled); + } + } + } + } +#else + internal void UpdateBoolEditor(bool enabled) + { + if (animatorParamBindings != null && targets && targets.IsAnimationSet) + { + IAnimatorWrapper animator = targets.GraphBuilder.WeaponWrapper; + if (animator == null || !animator.IsValid) + { + Log.Warning($"animator wrapper invalid!"); + return; + } + foreach (string str in animatorParamBindings) + { + if (str != null) + { + animator.SetBool(str, enabled); + } + } + } + } +#endif +} diff --git a/KFAttached/KFUtilAttached/TransformActivationBinding.cs.meta b/KFAttached/KFUtilAttached/TransformActivationBinding.cs.meta new file mode 100644 index 0000000..1f7e5ff --- /dev/null +++ b/KFAttached/KFUtilAttached/TransformActivationBinding.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2f2bc8183b119f347a32259111b5d1f2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponColorController.cs b/KFAttached/KFUtilAttached/WeaponColorController.cs new file mode 100644 index 0000000..a3371a4 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponColorController.cs @@ -0,0 +1,16 @@ +using UnityEngine; + +[AddComponentMenu("KFAttachments/Weapon Display Controllers/Weapon Color Controller")] +public class WeaponColorController : WeaponColorControllerBase +{ + [SerializeField] + protected Renderer[] renderers; + + public override bool setMaterialColor(int renderer_index, int material_index, int nameId, Color data) + { + if (renderers == null || renderers.Length <= renderer_index || !renderers[renderer_index].gameObject.activeInHierarchy || renderers[renderer_index].materials.Length <= material_index) + return false; + renderers[renderer_index].materials[material_index].SetColor(nameId, data); + return true; + } +} diff --git a/KFAttached/KFUtilAttached/WeaponColorController.cs.meta b/KFAttached/KFUtilAttached/WeaponColorController.cs.meta new file mode 100644 index 0000000..4e10292 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponColorController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dcfafc95230152c408908547f15202e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponColorControllerBase.cs b/KFAttached/KFUtilAttached/WeaponColorControllerBase.cs new file mode 100644 index 0000000..abf2380 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponColorControllerBase.cs @@ -0,0 +1,6 @@ +using UnityEngine; + +public abstract class WeaponColorControllerBase : MonoBehaviour +{ + public abstract bool setMaterialColor(int renderer_index, int material_index, int nameId, Color data); +} diff --git a/KFAttached/KFUtilAttached/WeaponColorControllerBase.cs.meta b/KFAttached/KFUtilAttached/WeaponColorControllerBase.cs.meta new file mode 100644 index 0000000..40ed4b1 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponColorControllerBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6fe7c9577b97dd8448e83857ceac21db +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponDataController.cs b/KFAttached/KFUtilAttached/WeaponDataController.cs new file mode 100644 index 0000000..8897ca6 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponDataController.cs @@ -0,0 +1,24 @@ +using UnityEngine; + +public class WeaponDataController : WeaponLabelControllerBase +{ + [SerializeField] + private WeaponDataHandlerBase[] handlers; + public override bool setLabelColor(int index, Color color) + { + if (handlers == null || index >= handlers.Length || index < 0 || !handlers[index] || !handlers[index].gameObject.activeSelf) + return false; + + handlers[index]?.SetColor(color); + return true; + } + + public override bool setLabelText(int index, string data) + { + if (handlers == null || index >= handlers.Length || index < 0 || !handlers[index] || !handlers[index].gameObject.activeSelf) + return false; + + handlers[index]?.SetText(data); + return true; + } +} \ No newline at end of file diff --git a/KFAttached/KFUtilAttached/WeaponDataController.cs.meta b/KFAttached/KFUtilAttached/WeaponDataController.cs.meta new file mode 100644 index 0000000..0e283fb --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponDataController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9f524ab568d21bf4d8f037fe0dee9c22 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponDataHandlerBase.cs b/KFAttached/KFUtilAttached/WeaponDataHandlerBase.cs new file mode 100644 index 0000000..a0ca076 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponDataHandlerBase.cs @@ -0,0 +1,7 @@ +using UnityEngine; + +public abstract class WeaponDataHandlerBase : MonoBehaviour +{ + public abstract void SetColor(Color color); + public abstract void SetText(string text); +} diff --git a/KFAttached/KFUtilAttached/WeaponDataHandlerBase.cs.meta b/KFAttached/KFUtilAttached/WeaponDataHandlerBase.cs.meta new file mode 100644 index 0000000..0796bfe --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponDataHandlerBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3657194e2634c8a4a8aea7e7becd0581 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponDataHandlerCanvasMask.cs b/KFAttached/KFUtilAttached/WeaponDataHandlerCanvasMask.cs new file mode 100644 index 0000000..a0b0daf --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponDataHandlerCanvasMask.cs @@ -0,0 +1,51 @@ +using UnityEngine; +using UnityEngine.UI; + +public class WeaponDataHandlerCanvasMask : WeaponDataHandlerBase +{ + [SerializeField] + protected RectMask2D mask; + [SerializeField] + protected Image image; + + protected float maxVal = 1, curVal = 1; + //protected bool updated = true; + + //protected virtual void OnEnable() + //{ + // LayoutRebuilder.MarkLayoutForRebuild(mask.rectTransform); + //} + + public override void SetColor(Color color) + { + image.color = color; + } + + public override void SetText(string text) + { + if (text.StartsWith("#")) + { + maxVal = Mathf.Max(float.Parse(text.Substring(1)), 1); + } + else + { + curVal = Mathf.Max(float.Parse(text), 0); + } + if (curVal > maxVal) + maxVal = curVal; + float perc = curVal / maxVal; + Vector4 padding = mask.padding; + padding.w = mask.rectTransform.rect.height * Mathf.Clamp01(1 - perc); + mask.padding = padding; + //updated = true; + } + + //protected virtual void LateUpdate() + //{ + // if (updated) + // { + // LayoutRebuilder.ForceRebuildLayoutImmediate(mask.rectTransform); + // updated = false; + // } + //} +} diff --git a/KFAttached/KFUtilAttached/WeaponDataHandlerCanvasMask.cs.meta b/KFAttached/KFUtilAttached/WeaponDataHandlerCanvasMask.cs.meta new file mode 100644 index 0000000..d10ff1a --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponDataHandlerCanvasMask.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 013c89968af9af042960a4fec49cd708 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponDataHandlerIndicator.cs b/KFAttached/KFUtilAttached/WeaponDataHandlerIndicator.cs new file mode 100644 index 0000000..154de68 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponDataHandlerIndicator.cs @@ -0,0 +1,71 @@ +using UnityEngine; + +public class WeaponDataHandlerIndicator : WeaponDataHandlerCanvasMask +{ + [SerializeField] + protected RectTransform indicator; + [SerializeField] + protected float offset; + [SerializeField, ColorUsage(true, true)] + protected Color normalColor; + [SerializeField, ColorUsage(true, true)] + protected Color warningColor; + + protected float level = 0; + + //private void Start() + //{ + // LayoutRebuilder.MarkLayoutForRebuild(indicator.parent.GetComponent()); + //} + + //protected override void OnEnable() + //{ + // base.OnEnable(); + // LayoutRebuilder.MarkLayoutForRebuild(indicator.parent.GetComponent()); + //} + + public override void SetText(string text) + { + if (text.StartsWith("$")) + { + level = Mathf.Clamp01(float.Parse(text.Substring(1)) / maxVal); + SetIndicatorPos(); + //updated = true; + } + else + { + float prevMax = maxVal; + base.SetText(text); + if (prevMax != maxVal) + { + level = prevMax * level / maxVal; + SetIndicatorPos(); + } + } + //Log.Out($"Setting text {text} max {maxVal} cur {curVal} level {level} indicator position {indicator.position.y} mask position {mask.padding.w}"); + if (curVal / maxVal < level) + { + SetColor(warningColor); + } + else + { + SetColor(normalColor); + } + } + + private void SetIndicatorPos() + { + Vector3 pos = indicator.anchoredPosition; + pos.y = mask.rectTransform.rect.height * level + offset; + indicator.anchoredPosition = pos; + } + + //protected override void LateUpdate() + //{ + // if (updated) + // { + // LayoutRebuilder.ForceRebuildLayoutImmediate(indicator.parent.GetComponent()); + // } + // base.LateUpdate(); + //} +} diff --git a/KFAttached/KFUtilAttached/WeaponDataHandlerIndicator.cs.meta b/KFAttached/KFUtilAttached/WeaponDataHandlerIndicator.cs.meta new file mode 100644 index 0000000..d9d10c3 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponDataHandlerIndicator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e993a995fe33f8742bd17bf4b5cae305 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponDataHandlerTMP.cs b/KFAttached/KFUtilAttached/WeaponDataHandlerTMP.cs new file mode 100644 index 0000000..5e002e7 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponDataHandlerTMP.cs @@ -0,0 +1,17 @@ +using TMPro; +using UnityEngine; + +public class WeaponDataHandlerTMP : WeaponDataHandlerBase +{ + [SerializeField] + private TMP_Text label; + public override void SetColor(Color color) + { + label.color = color; + } + + public override void SetText(string text) + { + label.SetText(text); + } +} diff --git a/KFAttached/KFUtilAttached/WeaponDataHandlerTMP.cs.meta b/KFAttached/KFUtilAttached/WeaponDataHandlerTMP.cs.meta new file mode 100644 index 0000000..d6a2f87 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponDataHandlerTMP.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6ee4e451d350e048954e14bbccf6e6b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponLabelController.cs b/KFAttached/KFUtilAttached/WeaponLabelController.cs new file mode 100644 index 0000000..0f518f7 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponLabelController.cs @@ -0,0 +1,24 @@ +using UnityEngine; + +[AddComponentMenu("KFAttachments/Weapon Display Controllers/Weapon Label Controller TextMesh")] +public class WeaponLabelController : WeaponLabelControllerBase +{ + [SerializeField] + private TextMesh[] labels; + + public override bool setLabelText(int index, string data) + { + if (labels == null || labels.Length <= index || !labels[index] || !labels[index].gameObject.activeSelf) + return false; + labels[index].text = data; + return true; + } + + public override bool setLabelColor(int index, Color color) + { + if (labels == null || labels.Length <= index || !labels[index] || !labels[index].gameObject.activeSelf) + return false; + labels[index].color = color; + return true; + } +} diff --git a/KFAttached/KFUtilAttached/WeaponLabelController.cs.meta b/KFAttached/KFUtilAttached/WeaponLabelController.cs.meta new file mode 100644 index 0000000..31f5a97 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponLabelController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a067c009a9175a34db35886e48ce0129 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponLabelControllerBase.cs b/KFAttached/KFUtilAttached/WeaponLabelControllerBase.cs new file mode 100644 index 0000000..4a9acb3 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponLabelControllerBase.cs @@ -0,0 +1,7 @@ +using UnityEngine; + +public abstract class WeaponLabelControllerBase : MonoBehaviour +{ + public abstract bool setLabelText(int index, string data); + public abstract bool setLabelColor(int index, Color color); +} diff --git a/KFAttached/KFUtilAttached/WeaponLabelControllerBase.cs.meta b/KFAttached/KFUtilAttached/WeaponLabelControllerBase.cs.meta new file mode 100644 index 0000000..8aca399 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponLabelControllerBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cc5547a942561564bb81d0ee893e4100 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponLabelControllerBatch.cs b/KFAttached/KFUtilAttached/WeaponLabelControllerBatch.cs new file mode 100644 index 0000000..1eefeb0 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponLabelControllerBatch.cs @@ -0,0 +1,36 @@ +using UnityEngine; + +namespace KFCommonUtilityLib.KFAttached.KFUtilAttached +{ + public class WeaponLabelControllerBatch : WeaponLabelControllerBase + { + [SerializeField] + private WeaponLabelControllerBase[] controllers; + + public override bool setLabelColor(int index, Color color) + { + bool flag = false; + foreach (var controller in controllers) + { + if (controller && controller.isActiveAndEnabled) + { + flag |= controller.setLabelColor(index, color); + } + } + return flag; + } + + public override bool setLabelText(int index, string data) + { + bool flag = false; + foreach (var controller in controllers) + { + if (controller && controller.isActiveAndEnabled) + { + flag |= controller.setLabelText(index, data); + } + } + return flag; + } + } +} diff --git a/KFAttached/KFUtilAttached/WeaponLabelControllerBatch.cs.meta b/KFAttached/KFUtilAttached/WeaponLabelControllerBatch.cs.meta new file mode 100644 index 0000000..6c89d6a --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponLabelControllerBatch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9bdf1f2fdda9aae4c80dd6e0bdba81d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponLabelControllerChargeUp.cs b/KFAttached/KFUtilAttached/WeaponLabelControllerChargeUp.cs new file mode 100644 index 0000000..62784f7 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponLabelControllerChargeUp.cs @@ -0,0 +1,61 @@ +using System.Collections; +using UnityEngine; + +[AddComponentMenu("KFAttachments/Weapon Display Controllers/Weapon Label Controller Charge Up")] +public class WeaponLabelControllerChargeUp : ApexWeaponHudControllerBase +{ + [SerializeField, Range(0.001f, 1f)] + protected float tickTime; + [SerializeField, Range(1, 1000)] + protected int updateTicks = 1; + protected Coroutine curChargeProc; + protected bool isChargeRunning = false; + internal void StartChargeUp() + { + if (shaderEnabled && (curChargeProc == null || !isChargeRunning)) + curChargeProc = StartCoroutine(ChargeUp()); + } + + internal void StopChargeUp() + { + if (shaderEnabled && curChargeProc != null) + { + StopCoroutine(curChargeProc); + curChargeProc = null; + isChargeRunning = false; + } + } + + protected override void OnDisable() + { + StopChargeUp(); + } + + private IEnumerator ChargeUp() + { + isChargeRunning = true; + float chargeLeap = (float)dataArray[0] / updateTicks; + int[] chargeArray = new int[4]; + float curChargeCount = 0; + dataArray.CopyTo(chargeArray, 0); + int max = dataArray[1]; + chargeArray[1] = (int)curChargeCount; + while (chargeArray[1] <= max) + { + Dispatch(chargeArray); + if (chargeArray[1] == max) + break; + yield return new WaitForSecondsRealtime(tickTime); + max = dataArray[1]; + curChargeCount += chargeLeap; + chargeArray[1] = Mathf.Min((int)curChargeCount, max); + } + isChargeRunning = false; + yield break; + } + + protected override bool CanDispatch() + { + return base.CanDispatch() && !isChargeRunning; + } +} diff --git a/KFAttached/KFUtilAttached/WeaponLabelControllerChargeUp.cs.meta b/KFAttached/KFUtilAttached/WeaponLabelControllerChargeUp.cs.meta new file mode 100644 index 0000000..1d0e1d4 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponLabelControllerChargeUp.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 24181b5d7224798438ea0bb73892de70 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponLabelControllerDevotion.cs b/KFAttached/KFUtilAttached/WeaponLabelControllerDevotion.cs new file mode 100644 index 0000000..f0b0fb4 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponLabelControllerDevotion.cs @@ -0,0 +1,25 @@ +using UnityEngine; + +[AddComponentMenu("KFAttachments/Weapon Display Controllers/Weapon Label Controller Devotion")] +public class WeaponLabelControllerDevotion : WeaponLabelControllerBase +{ + [SerializeField] + private ApexWeaponHudControllerBase[] controllers; + public override bool setLabelColor(int index, Color color) + { + if (controllers == null || index >= controllers.Length || !controllers[index] || !controllers[index].gameObject.activeSelf) + return false; + + controllers[index].SetColor(color); + return true; + } + + public override bool setLabelText(int index, string data) + { + if (controllers == null || index >= controllers.Length || !controllers[index] || !controllers[index].gameObject.activeSelf) + return false; + + controllers[index].SetText(data); + return true; + } +} diff --git a/KFAttached/KFUtilAttached/WeaponLabelControllerDevotion.cs.meta b/KFAttached/KFUtilAttached/WeaponLabelControllerDevotion.cs.meta new file mode 100644 index 0000000..a7bc76d --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponLabelControllerDevotion.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6bc6e113f61659f489e67db4beb49b7d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/KFUtilAttached/WeaponTextProController.cs b/KFAttached/KFUtilAttached/WeaponTextProController.cs new file mode 100644 index 0000000..ba73e82 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponTextProController.cs @@ -0,0 +1,25 @@ +using TMPro; +using UnityEngine; + +[AddComponentMenu("KFAttachments/Weapon Display Controllers/Weapon Text Controller TMP")] +public class WeaponTextProController : WeaponLabelControllerBase +{ + [SerializeField] + private TMP_Text[] labels; + + public override bool setLabelText(int index, string data) + { + if (labels == null || labels.Length <= index || !labels[index] || !labels[index].gameObject.activeSelf) + return false; + labels[index].SetText(data); + return true; + } + + public override bool setLabelColor(int index, Color color) + { + if (labels == null || labels.Length <= index || !labels[index] || !labels[index].gameObject.activeSelf) + return false; + labels[index].color = color; + return true; + } +} diff --git a/KFAttached/KFUtilAttached/WeaponTextProController.cs.meta b/KFAttached/KFUtilAttached/WeaponTextProController.cs.meta new file mode 100644 index 0000000..a63b0c5 --- /dev/null +++ b/KFAttached/KFUtilAttached/WeaponTextProController.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 93439c08074a2ef42b5c4da798001216 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/LeanTween.meta b/KFAttached/LeanTween.meta new file mode 100644 index 0000000..eb22f9c --- /dev/null +++ b/KFAttached/LeanTween.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5e6a0fa47acf54892bbdae89028eaec3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/LeanTween/Framework.meta b/KFAttached/LeanTween/Framework.meta new file mode 100644 index 0000000..5e492d8 --- /dev/null +++ b/KFAttached/LeanTween/Framework.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a3f23ec8eb7c24f0bbb1d41bf96c154f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/LeanTween/Framework/LTDescr.cs b/KFAttached/LeanTween/Framework/LTDescr.cs new file mode 100644 index 0000000..3de2355 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LTDescr.cs @@ -0,0 +1,2695 @@ +//namespace DentedPixel{ +using System; +using UnityEngine; + +/** +* Internal Representation of a Tween
+*
+* This class represents all of the optional parameters you can pass to a method (it also represents the internal representation of the tween).

+* Optional Parameters are passed at the end of every method:
+*
+*   Example:
+*   LeanTween.moveX( gameObject, 1f, 1f).setEase(
LeanTweenType.easeInQuad ).setDelay(1f);
+*
+* You can pass the optional parameters in any order, and chain on as many as you wish.
+* You can also pass parameters at a later time by saving a reference to what is returned.
+*
+* Retrieve a unique id for the tween by using the "id" property. You can pass this to LeanTween.pause, LeanTween.resume, LeanTween.cancel, LeanTween.isTweening methods
+*
+*   

Example:

+*   int id = LeanTween.moveX(gameObject, 1f, 3f).id;
+*
  // pause a specific tween
+*   LeanTween.pause(id);
+*
  // resume later
+*   LeanTween.resume(id);
+*
  // check if it is tweening before kicking of a new tween
+*   if( LeanTween.isTweening( id ) ){
+*       LeanTween.cancel( id );
+*       LeanTween.moveZ(gameObject, 10f, 3f);
+*   }
+* @class LTDescr +* @constructor +*/ +public class LTDescr +{ + public bool toggle; + public bool useEstimatedTime; + public bool useFrames; + public bool useManualTime; + public bool usesNormalDt; + public bool hasInitiliazed; + public bool hasExtraOnCompletes; + public bool hasPhysics; + public bool onCompleteOnRepeat; + public bool onCompleteOnStart; + public bool useRecursion; + public float ratioPassed; + public float passed; + public float delay; + public float time; + public float speed; + public float lastVal; + private uint _id; + public int loopCount; + public uint counter = uint.MaxValue; + public float direction; + public float directionLast; + public float overshoot; + public float period; + public float scale; + public bool destroyOnComplete; + public Transform trans; + internal Vector3 fromInternal; + public Vector3 from { get { return this.fromInternal; } set { this.fromInternal = value; } } + internal Vector3 toInternal; + public Vector3 to { get { return this.toInternal; } set { this.toInternal = value; } } + internal Vector3 diff; + internal Vector3 diffDiv2; + public TweenAction type; + private LeanTweenType easeType; + public LeanTweenType loopType; + + public bool hasUpdateCallback; + + public EaseTypeDelegate easeMethod; + public ActionMethodDelegate easeInternal { get; set; } + public ActionMethodDelegate initInternal { get; set; } + public delegate Vector3 EaseTypeDelegate(); + public delegate void ActionMethodDelegate(); +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 + public SpriteRenderer spriteRen; +#endif + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 + public RectTransform rectTransform; + public UnityEngine.UI.Text uiText; + public UnityEngine.UI.Image uiImage; + public UnityEngine.UI.RawImage rawImage; + public UnityEngine.Sprite[] sprites; +#endif + + // Convenience Getters + public Transform toTrans + { + get + { + return optional.toTrans; + } + } + + public LTDescrOptional _optional = new LTDescrOptional(); + + public override string ToString() + { + return (trans != null ? "name:" + trans.gameObject.name : "gameObject:null") + " toggle:" + toggle + " passed:" + passed + " time:" + time + " delay:" + delay + " direction:" + direction + " from:" + from + " to:" + to + " diff:" + diff + " type:" + type + " ease:" + easeType + " useEstimatedTime:" + useEstimatedTime + " id:" + id + " hasInitiliazed:" + hasInitiliazed; + } + + public LTDescr() + { + + } + + [System.Obsolete("Use 'LeanTween.cancel( id )' instead")] + public LTDescr cancel(GameObject gameObject) + { + // Debug.Log("canceling id:"+this._id+" this.uniqueId:"+this.uniqueId+" go:"+this.trans.gameObject); + if (gameObject == this.trans.gameObject) + LeanTween.removeTween((int)this._id, this.uniqueId); + return this; + } + + public int uniqueId + { + get + { + uint toId = _id | counter << 16; + + /*uint backId = toId & 0xFFFF; + uint backCounter = toId >> 16; + if(_id!=backId || backCounter!=counter){ + Debug.LogError("BAD CONVERSION toId:"+_id); + }*/ + + return (int)toId; + } + } + + public int id + { + get + { + return uniqueId; + } + } + + public LTDescrOptional optional + { + get + { + return _optional; + } + set + { + this._optional = value; + } + } + + public void reset() + { + this.toggle = this.useRecursion = this.usesNormalDt = true; + this.trans = null; + this.spriteRen = null; + this.passed = this.delay = this.lastVal = 0.0f; + this.hasUpdateCallback = this.useEstimatedTime = this.useFrames = this.hasInitiliazed = this.onCompleteOnRepeat = this.destroyOnComplete = this.onCompleteOnStart = this.useManualTime = this.hasExtraOnCompletes = false; + this.easeType = LeanTweenType.linear; + this.loopType = LeanTweenType.once; + this.loopCount = 0; + this.direction = this.directionLast = this.overshoot = this.scale = 1.0f; + this.period = 0.3f; + this.speed = -1f; + this.easeMethod = this.easeLinear; + this.from = this.to = Vector3.zero; + this._optional.reset(); + } + + // Initialize and Internal Methods + + public LTDescr setFollow() + { + this.type = TweenAction.FOLLOW; + return this; + } + + public LTDescr setMoveX() + { + this.type = TweenAction.MOVE_X; + this.initInternal = () => { this.fromInternal.x = trans.position.x; }; + this.easeInternal = () => { trans.position = new Vector3(easeMethod().x, trans.position.y, trans.position.z); }; + return this; + } + + public LTDescr setMoveY() + { + this.type = TweenAction.MOVE_Y; + this.initInternal = () => { this.fromInternal.x = trans.position.y; }; + this.easeInternal = () => { trans.position = new Vector3(trans.position.x, easeMethod().x, trans.position.z); }; + return this; + } + + public LTDescr setMoveZ() + { + this.type = TweenAction.MOVE_Z; + this.initInternal = () => { this.fromInternal.x = trans.position.z; }; ; + this.easeInternal = () => { trans.position = new Vector3(trans.position.x, trans.position.y, easeMethod().x); }; + return this; + } + + public LTDescr setMoveLocalX() + { + this.type = TweenAction.MOVE_LOCAL_X; + this.initInternal = () => { this.fromInternal.x = trans.localPosition.x; }; + this.easeInternal = () => { trans.localPosition = new Vector3(easeMethod().x, trans.localPosition.y, trans.localPosition.z); }; + return this; + } + + public LTDescr setMoveLocalY() + { + this.type = TweenAction.MOVE_LOCAL_Y; + this.initInternal = () => { this.fromInternal.x = trans.localPosition.y; }; + this.easeInternal = () => { trans.localPosition = new Vector3(trans.localPosition.x, easeMethod().x, trans.localPosition.z); }; + return this; + } + + public LTDescr setMoveLocalZ() + { + this.type = TweenAction.MOVE_LOCAL_Z; + this.initInternal = () => { this.fromInternal.x = trans.localPosition.z; }; + this.easeInternal = () => { trans.localPosition = new Vector3(trans.localPosition.x, trans.localPosition.y, easeMethod().x); }; + return this; + } + + private void initFromInternal() { this.fromInternal.x = 0; } + + public LTDescr setOffset(Vector3 offset) + { + this.toInternal = offset; + return this; + } + + public LTDescr setMoveCurved() + { + this.type = TweenAction.MOVE_CURVED; + this.initInternal = this.initFromInternal; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + if (this._optional.path.orientToPath) + { + if (this._optional.path.orientToPath2d) + { + this._optional.path.place2d(trans, val); + } + else + { + this._optional.path.place(trans, val); + } + } + else + { + trans.position = this._optional.path.point(val); + } + }; + return this; + } + + public LTDescr setMoveCurvedLocal() + { + this.type = TweenAction.MOVE_CURVED_LOCAL; + this.initInternal = this.initFromInternal; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + if (this._optional.path.orientToPath) + { + if (this._optional.path.orientToPath2d) + { + this._optional.path.placeLocal2d(trans, val); + } + else + { + this._optional.path.placeLocal(trans, val); + } + } + else + { + trans.localPosition = this._optional.path.point(val); + } + }; + return this; + } + + public LTDescr setMoveSpline() + { + this.type = TweenAction.MOVE_SPLINE; + this.initInternal = this.initFromInternal; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + if (this._optional.spline.orientToPath) + { + if (this._optional.spline.orientToPath2d) + { + this._optional.spline.place2d(trans, val); + } + else + { + this._optional.spline.place(trans, val); + } + } + else + { + trans.position = this._optional.spline.point(val); + } + }; + return this; + } + + public LTDescr setMoveSplineLocal() + { + this.type = TweenAction.MOVE_SPLINE_LOCAL; + this.initInternal = this.initFromInternal; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + if (this._optional.spline.orientToPath) + { + if (this._optional.spline.orientToPath2d) + { + this._optional.spline.placeLocal2d(trans, val); + } + else + { + this._optional.spline.placeLocal(trans, val); + } + } + else + { + trans.localPosition = this._optional.spline.point(val); + } + }; + return this; + } + + public LTDescr setScaleX() + { + this.type = TweenAction.SCALE_X; + this.initInternal = () => { this.fromInternal.x = trans.localScale.x; }; + this.easeInternal = () => { trans.localScale = new Vector3(easeMethod().x, trans.localScale.y, trans.localScale.z); }; + return this; + } + + public LTDescr setScaleY() + { + this.type = TweenAction.SCALE_Y; + this.initInternal = () => { this.fromInternal.x = trans.localScale.y; }; + this.easeInternal = () => { trans.localScale = new Vector3(trans.localScale.x, easeMethod().x, trans.localScale.z); }; + return this; + } + + public LTDescr setScaleZ() + { + this.type = TweenAction.SCALE_Z; + this.initInternal = () => { this.fromInternal.x = trans.localScale.z; }; + this.easeInternal = () => { trans.localScale = new Vector3(trans.localScale.x, trans.localScale.y, easeMethod().x); }; + return this; + } + + public LTDescr setRotateX() + { + this.type = TweenAction.ROTATE_X; + this.initInternal = () => { this.fromInternal.x = trans.eulerAngles.x; this.toInternal.x = LeanTween.closestRot(this.fromInternal.x, this.toInternal.x); }; + this.easeInternal = () => { trans.eulerAngles = new Vector3(easeMethod().x, trans.eulerAngles.y, trans.eulerAngles.z); }; + return this; + } + + public LTDescr setRotateY() + { + this.type = TweenAction.ROTATE_Y; + this.initInternal = () => { this.fromInternal.x = trans.eulerAngles.y; this.toInternal.x = LeanTween.closestRot(this.fromInternal.x, this.toInternal.x); }; + this.easeInternal = () => { trans.eulerAngles = new Vector3(trans.eulerAngles.x, easeMethod().x, trans.eulerAngles.z); }; + return this; + } + + public LTDescr setRotateZ() + { + this.type = TweenAction.ROTATE_Z; + this.initInternal = () => + { + this.fromInternal.x = trans.eulerAngles.z; + this.toInternal.x = LeanTween.closestRot(this.fromInternal.x, this.toInternal.x); + }; + this.easeInternal = () => { trans.eulerAngles = new Vector3(trans.eulerAngles.x, trans.eulerAngles.y, easeMethod().x); }; + return this; + } + + public LTDescr setRotateAround() + { + this.type = TweenAction.ROTATE_AROUND; + this.initInternal = () => + { + this.fromInternal.x = 0f; + this._optional.origRotation = trans.rotation; + }; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + Vector3 origPos = trans.localPosition; + Vector3 rotateAroundPt = (Vector3)trans.TransformPoint(this._optional.point); + // Debug.Log("this._optional.point:"+this._optional.point); + trans.RotateAround(rotateAroundPt, this._optional.axis, -this._optional.lastVal); + Vector3 diff = origPos - trans.localPosition; + + trans.localPosition = origPos - diff; // Subtract the amount the object has been shifted over by the rotate, to get it back to it's orginal position + trans.rotation = this._optional.origRotation; + + rotateAroundPt = (Vector3)trans.TransformPoint(this._optional.point); + trans.RotateAround(rotateAroundPt, this._optional.axis, val); + + this._optional.lastVal = val; + }; + return this; + } + + public LTDescr setRotateAroundLocal() + { + this.type = TweenAction.ROTATE_AROUND_LOCAL; + this.initInternal = () => + { + this.fromInternal.x = 0f; + this._optional.origRotation = trans.localRotation; + }; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + Vector3 origPos = trans.localPosition; + trans.RotateAround((Vector3)trans.TransformPoint(this._optional.point), trans.TransformDirection(this._optional.axis), -this._optional.lastVal); + Vector3 diff = origPos - trans.localPosition; + + trans.localPosition = origPos - diff; // Subtract the amount the object has been shifted over by the rotate, to get it back to it's orginal position + trans.localRotation = this._optional.origRotation; + Vector3 rotateAroundPt = (Vector3)trans.TransformPoint(this._optional.point); + trans.RotateAround(rotateAroundPt, trans.TransformDirection(this._optional.axis), val); + + this._optional.lastVal = val; + }; + return this; + } + + public LTDescr setAlpha() + { + this.type = TweenAction.ALPHA; + this.initInternal = () => + { +#if UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 + if(trans.gameObject.renderer){ this.fromInternal.x = trans.gameObject.renderer.material.color.a; }else if(trans.childCount>0){ foreach (Transform child in trans) { if(child.gameObject.renderer!=null){ Color col = child.gameObject.renderer.material.color; this.fromInternal.x = col.a; break; }}} + this.easeInternal = this.alpha; + break; +#else + SpriteRenderer ren = trans.GetComponent(); + if (ren != null) + { + this.fromInternal.x = ren.color.a; + } + else + { + if (trans.GetComponent() != null && trans.GetComponent().material.HasProperty("_Color")) + { + this.fromInternal.x = trans.GetComponent().material.color.a; + } + else if (trans.GetComponent() != null && trans.GetComponent().material.HasProperty("_TintColor")) + { + Color col = trans.GetComponent().material.GetColor("_TintColor"); + this.fromInternal.x = col.a; + } + else if (trans.childCount > 0) + { + foreach (Transform child in trans) + { + if (child.gameObject.GetComponent() != null) + { + Color col = child.gameObject.GetComponent().material.color; + this.fromInternal.x = col.a; + break; + } + } + } + } +#endif + + this.easeInternal = () => + { + val = easeMethod().x; +#if UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 + alphaRecursive(this.trans, val, this.useRecursion); +#else + if (this.spriteRen != null) + { + this.spriteRen.color = new Color(this.spriteRen.color.r, this.spriteRen.color.g, this.spriteRen.color.b, val); + alphaRecursiveSprite(this.trans, val); + } + else + { + alphaRecursive(this.trans, val, this.useRecursion); + } +#endif + }; + + }; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; +#if UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 + alphaRecursive(this.trans, val, this.useRecursion); +#else + if (this.spriteRen != null) + { + this.spriteRen.color = new Color(this.spriteRen.color.r, this.spriteRen.color.g, this.spriteRen.color.b, val); + alphaRecursiveSprite(this.trans, val); + } + else + { + alphaRecursive(this.trans, val, this.useRecursion); + } +#endif + }; + return this; + } + + public LTDescr setTextAlpha() + { + this.type = TweenAction.TEXT_ALPHA; + this.initInternal = () => + { + this.uiText = trans.GetComponent(); + this.fromInternal.x = this.uiText != null ? this.uiText.color.a : 1f; + }; + this.easeInternal = () => { textAlphaRecursive(trans, easeMethod().x, this.useRecursion); }; + return this; + } + + public LTDescr setAlphaVertex() + { + this.type = TweenAction.ALPHA_VERTEX; + this.initInternal = () => { this.fromInternal.x = trans.GetComponent().mesh.colors32[0].a; }; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + Mesh mesh = trans.GetComponent().mesh; + Vector3[] vertices = mesh.vertices; + Color32[] colors = new Color32[vertices.Length]; + if (colors.Length == 0) + { //MaxFW fix: add vertex colors if the mesh doesn't have any + Color32 transparentWhiteColor32 = new Color32(0xff, 0xff, 0xff, 0x00); + colors = new Color32[mesh.vertices.Length]; + for (int k = 0; k < colors.Length; k++) + colors[k] = transparentWhiteColor32; + mesh.colors32 = colors; + }// fix end + Color32 c = mesh.colors32[0]; + c = new Color(c.r, c.g, c.b, val); + for (int k = 0; k < vertices.Length; k++) + colors[k] = c; + mesh.colors32 = colors; + }; + return this; + } + + public LTDescr setColor() + { + this.type = TweenAction.COLOR; + this.initInternal = () => + { +#if UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 + if(trans.gameObject.renderer){ + this.setFromColor( trans.gameObject.renderer.material.color ); + }else if(trans.childCount>0){ + foreach (Transform child in trans) { + if(child.gameObject.renderer!=null){ + this.setFromColor( child.gameObject.renderer.material.color ); + break; + } + } + } +#else + SpriteRenderer renColor = trans.GetComponent(); + if (renColor != null) + { + this.setFromColor(renColor.color); + } + else + { + if (trans.GetComponent() != null && trans.GetComponent().material.HasProperty("_Color")) + { + Color col = trans.GetComponent().material.color; + this.setFromColor(col); + } + else if (trans.GetComponent() != null && trans.GetComponent().material.HasProperty("_TintColor")) + { + Color col = trans.GetComponent().material.GetColor("_TintColor"); + this.setFromColor(col); + } + else if (trans.childCount > 0) + { + foreach (Transform child in trans) + { + if (child.gameObject.GetComponent() != null) + { + Color col = child.gameObject.GetComponent().material.color; + this.setFromColor(col); + break; + } + } + } + } +#endif + }; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + Color toColor = tweenColor(this, val); + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 + + if (this.spriteRen != null) + { + this.spriteRen.color = toColor; + colorRecursiveSprite(trans, toColor); + } + else + { +#endif + // Debug.Log("val:"+val+" tween:"+tween+" tween.diff:"+tween.diff); + if (this.type == TweenAction.COLOR) + colorRecursive(trans, toColor, this.useRecursion); + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 + } +#endif + if (dt != 0f && this._optional.onUpdateColor != null) + { + this._optional.onUpdateColor(toColor); + } + else if (dt != 0f && this._optional.onUpdateColorObject != null) + { + this._optional.onUpdateColorObject(toColor, this._optional.onUpdateParam); + } + }; + return this; + } + + public LTDescr setCallbackColor() + { + this.type = TweenAction.CALLBACK_COLOR; + this.initInternal = () => { this.diff = new Vector3(1.0f, 0.0f, 0.0f); }; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + Color toColor = tweenColor(this, val); + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 + if (this.spriteRen != null) + { + this.spriteRen.color = toColor; + colorRecursiveSprite(trans, toColor); + } + else + { +#endif + // Debug.Log("val:"+val+" tween:"+tween+" tween.diff:"+tween.diff); + if (this.type == TweenAction.COLOR) + colorRecursive(trans, toColor, this.useRecursion); + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 + } +#endif + if (dt != 0f && this._optional.onUpdateColor != null) + { + this._optional.onUpdateColor(toColor); + } + else if (dt != 0f && this._optional.onUpdateColorObject != null) + { + this._optional.onUpdateColorObject(toColor, this._optional.onUpdateParam); + } + }; + return this; + } + + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 + + public LTDescr setTextColor() + { + this.type = TweenAction.TEXT_COLOR; + this.initInternal = () => + { + this.uiText = trans.GetComponent(); + this.setFromColor(this.uiText != null ? this.uiText.color : Color.white); + }; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + Color toColor = tweenColor(this, val); + this.uiText.color = toColor; + if (dt != 0f && this._optional.onUpdateColor != null) + this._optional.onUpdateColor(toColor); + + if (this.useRecursion && trans.childCount > 0) + textColorRecursive(this.trans, toColor); + }; + return this; + } + + public LTDescr setCanvasAlpha() + { + this.type = TweenAction.CANVAS_ALPHA; + this.initInternal = () => + { + this.uiImage = trans.GetComponent(); + if (this.uiImage != null) + { + this.fromInternal.x = this.uiImage.color.a; + } + else + { + this.rawImage = trans.GetComponent(); + if (this.rawImage != null) + { + this.fromInternal.x = this.rawImage.color.a; + } + else + { + this.fromInternal.x = 1f; + } + } + + }; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + if (this.uiImage != null) + { + Color c = this.uiImage.color; c.a = val; this.uiImage.color = c; + } + else if (this.rawImage != null) + { + Color c = this.rawImage.color; c.a = val; this.rawImage.color = c; + } + if (this.useRecursion) + { + alphaRecursive(this.rectTransform, val, 0); + textAlphaChildrenRecursive(this.rectTransform, val); + } + }; + return this; + } + + public LTDescr setCanvasGroupAlpha() + { + this.type = TweenAction.CANVASGROUP_ALPHA; + this.initInternal = () => { this.fromInternal.x = trans.GetComponent().alpha; }; + this.easeInternal = () => { this.trans.GetComponent().alpha = easeMethod().x; }; + return this; + } + + public LTDescr setCanvasColor() + { + this.type = TweenAction.CANVAS_COLOR; + this.initInternal = () => + { + this.uiImage = trans.GetComponent(); + if (this.uiImage == null) + { + this.rawImage = trans.GetComponent(); + this.setFromColor(this.rawImage != null ? this.rawImage.color : Color.white); + } + else + { + this.setFromColor(this.uiImage.color); + } + + }; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + Color toColor = tweenColor(this, val); + if (this.uiImage != null) + { + this.uiImage.color = toColor; + } + else if (this.rawImage != null) + { + this.rawImage.color = toColor; + } + + if (dt != 0f && this._optional.onUpdateColor != null) + this._optional.onUpdateColor(toColor); + + if (this.useRecursion) + colorRecursive(this.rectTransform, toColor); + }; + return this; + } + + public LTDescr setCanvasMoveX() + { + this.type = TweenAction.CANVAS_MOVE_X; + this.initInternal = () => { this.fromInternal.x = this.rectTransform.anchoredPosition3D.x; }; + this.easeInternal = () => { Vector3 c = this.rectTransform.anchoredPosition3D; this.rectTransform.anchoredPosition3D = new Vector3(easeMethod().x, c.y, c.z); }; + return this; + } + + public LTDescr setCanvasMoveY() + { + this.type = TweenAction.CANVAS_MOVE_Y; + this.initInternal = () => { this.fromInternal.x = this.rectTransform.anchoredPosition3D.y; }; + this.easeInternal = () => { Vector3 c = this.rectTransform.anchoredPosition3D; this.rectTransform.anchoredPosition3D = new Vector3(c.x, easeMethod().x, c.z); }; + return this; + } + + public LTDescr setCanvasMoveZ() + { + this.type = TweenAction.CANVAS_MOVE_Z; + this.initInternal = () => { this.fromInternal.x = this.rectTransform.anchoredPosition3D.z; }; + this.easeInternal = () => { Vector3 c = this.rectTransform.anchoredPosition3D; this.rectTransform.anchoredPosition3D = new Vector3(c.x, c.y, easeMethod().x); }; + return this; + } + + private void initCanvasRotateAround() + { + this.lastVal = 0.0f; + this.fromInternal.x = 0.0f; + this._optional.origRotation = this.rectTransform.rotation; + } + + public LTDescr setCanvasRotateAround() + { + this.type = TweenAction.CANVAS_ROTATEAROUND; + this.initInternal = this.initCanvasRotateAround; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + RectTransform rect = this.rectTransform; + Vector3 origPos = rect.localPosition; + rect.RotateAround((Vector3)rect.TransformPoint(this._optional.point), this._optional.axis, -val); + Vector3 diff = origPos - rect.localPosition; + + rect.localPosition = origPos - diff; // Subtract the amount the object has been shifted over by the rotate, to get it back to it's orginal position + rect.rotation = this._optional.origRotation; + rect.RotateAround((Vector3)rect.TransformPoint(this._optional.point), this._optional.axis, val); + }; + return this; + } + + public LTDescr setCanvasRotateAroundLocal() + { + this.type = TweenAction.CANVAS_ROTATEAROUND_LOCAL; + this.initInternal = this.initCanvasRotateAround; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + RectTransform rect = this.rectTransform; + Vector3 origPos = rect.localPosition; + rect.RotateAround((Vector3)rect.TransformPoint(this._optional.point), rect.TransformDirection(this._optional.axis), -val); + Vector3 diff = origPos - rect.localPosition; + + rect.localPosition = origPos - diff; // Subtract the amount the object has been shifted over by the rotate, to get it back to it's orginal position + rect.rotation = this._optional.origRotation; + rect.RotateAround((Vector3)rect.TransformPoint(this._optional.point), rect.TransformDirection(this._optional.axis), val); + }; + return this; + } + + public LTDescr setCanvasPlaySprite() + { + this.type = TweenAction.CANVAS_PLAYSPRITE; + this.initInternal = () => + { + this.uiImage = trans.GetComponent(); + this.fromInternal.x = 0f; + }; + this.easeInternal = () => + { + newVect = easeMethod(); + val = newVect.x; + int frame = (int)Mathf.Round(val); + this.uiImage.sprite = this.sprites[frame]; + }; + return this; + } + + public LTDescr setCanvasMove() + { + this.type = TweenAction.CANVAS_MOVE; + this.initInternal = () => { this.fromInternal = this.rectTransform.anchoredPosition3D; }; + this.easeInternal = () => { this.rectTransform.anchoredPosition3D = easeMethod(); }; + return this; + } + + public LTDescr setCanvasScale() + { + this.type = TweenAction.CANVAS_SCALE; + this.initInternal = () => { this.from = this.rectTransform.localScale; }; + this.easeInternal = () => { this.rectTransform.localScale = easeMethod(); }; + return this; + } + + public LTDescr setCanvasSizeDelta() + { + this.type = TweenAction.CANVAS_SIZEDELTA; + this.initInternal = () => { this.from = this.rectTransform.sizeDelta; }; + this.easeInternal = () => { this.rectTransform.sizeDelta = easeMethod(); }; + return this; + } +#endif + + private void callback() { newVect = easeMethod(); val = newVect.x; } + + public LTDescr setCallback() + { + this.type = TweenAction.CALLBACK; + this.initInternal = () => { }; + this.easeInternal = this.callback; + return this; + } + public LTDescr setValue3() + { + this.type = TweenAction.VALUE3; + this.initInternal = () => { }; + this.easeInternal = this.callback; + return this; + } + + public LTDescr setMove() + { + this.type = TweenAction.MOVE; + this.initInternal = () => { this.from = trans.position; }; + this.easeInternal = () => + { + newVect = easeMethod(); + trans.position = newVect; + }; + return this; + } + + public LTDescr setMoveLocal() + { + this.type = TweenAction.MOVE_LOCAL; + this.initInternal = () => { this.from = trans.localPosition; }; + this.easeInternal = () => + { + newVect = easeMethod(); + trans.localPosition = newVect; + }; + return this; + } + + public LTDescr setMoveToTransform() + { + this.type = TweenAction.MOVE_TO_TRANSFORM; + this.initInternal = () => { this.from = trans.position; }; + this.easeInternal = () => + { + this.to = this._optional.toTrans.position; + this.diff = this.to - this.from; + this.diffDiv2 = this.diff * 0.5f; + + newVect = easeMethod(); + this.trans.position = newVect; + }; + return this; + } + + public LTDescr setRotate() + { + this.type = TweenAction.ROTATE; + this.initInternal = () => { this.from = trans.eulerAngles; this.to = new Vector3(LeanTween.closestRot(this.fromInternal.x, this.toInternal.x), LeanTween.closestRot(this.from.y, this.to.y), LeanTween.closestRot(this.from.z, this.to.z)); }; + this.easeInternal = () => + { + newVect = easeMethod(); + trans.eulerAngles = newVect; + }; + return this; + } + + public LTDescr setRotateLocal() + { + this.type = TweenAction.ROTATE_LOCAL; + this.initInternal = () => { this.from = trans.localEulerAngles; this.to = new Vector3(LeanTween.closestRot(this.fromInternal.x, this.toInternal.x), LeanTween.closestRot(this.from.y, this.to.y), LeanTween.closestRot(this.from.z, this.to.z)); }; + this.easeInternal = () => + { + newVect = easeMethod(); + trans.localEulerAngles = newVect; + }; + return this; + } + + public LTDescr setScale() + { + this.type = TweenAction.SCALE; + this.initInternal = () => { this.from = trans.localScale; }; + this.easeInternal = () => + { + newVect = easeMethod(); + trans.localScale = newVect; + }; + return this; + } + + public LTDescr setGUIMove() + { + this.type = TweenAction.GUI_MOVE; + this.initInternal = () => { this.from = new Vector3(this._optional.ltRect.rect.x, this._optional.ltRect.rect.y, 0); }; + this.easeInternal = () => { Vector3 v = easeMethod(); this._optional.ltRect.rect = new Rect(v.x, v.y, this._optional.ltRect.rect.width, this._optional.ltRect.rect.height); }; + return this; + } + + public LTDescr setGUIMoveMargin() + { + this.type = TweenAction.GUI_MOVE_MARGIN; + this.initInternal = () => { this.from = new Vector2(this._optional.ltRect.margin.x, this._optional.ltRect.margin.y); }; + this.easeInternal = () => { Vector3 v = easeMethod(); this._optional.ltRect.margin = new Vector2(v.x, v.y); }; + return this; + } + + public LTDescr setGUIScale() + { + this.type = TweenAction.GUI_SCALE; + this.initInternal = () => { this.from = new Vector3(this._optional.ltRect.rect.width, this._optional.ltRect.rect.height, 0); }; + this.easeInternal = () => { Vector3 v = easeMethod(); this._optional.ltRect.rect = new Rect(this._optional.ltRect.rect.x, this._optional.ltRect.rect.y, v.x, v.y); }; + return this; + } + + public LTDescr setGUIAlpha() + { + this.type = TweenAction.GUI_ALPHA; + this.initInternal = () => { this.fromInternal.x = this._optional.ltRect.alpha; }; + this.easeInternal = () => { this._optional.ltRect.alpha = easeMethod().x; }; + return this; + } + + public LTDescr setGUIRotate() + { + this.type = TweenAction.GUI_ROTATE; + this.initInternal = () => + { + if (this._optional.ltRect.rotateEnabled == false) + { + this._optional.ltRect.rotateEnabled = true; + this._optional.ltRect.resetForRotation(); + } + + this.fromInternal.x = this._optional.ltRect.rotation; + }; + this.easeInternal = () => { this._optional.ltRect.rotation = easeMethod().x; }; + return this; + } + + public LTDescr setDelayedSound() + { + this.type = TweenAction.DELAYED_SOUND; + this.initInternal = () => { this.hasExtraOnCompletes = true; }; + this.easeInternal = this.callback; + return this; + } + + public LTDescr setTarget(Transform trans) + { + this.optional.toTrans = trans; + return this; + } + + private void init() + { + this.hasInitiliazed = true; + + usesNormalDt = !(useEstimatedTime || useManualTime || useFrames); // only set this to true if it uses non of the other timing modes + + if (useFrames) + this.optional.initFrameCount = Time.frameCount; + + if (this.time <= 0f) // avoid dividing by zero + this.time = Mathf.Epsilon; + + if (this.initInternal != null) + this.initInternal(); + + this.diff = this.to - this.from; + this.diffDiv2 = this.diff * 0.5f; + + if (this._optional.onStart != null) + this._optional.onStart(); + + if (this.onCompleteOnStart) + callOnCompletes(); + + if (this.speed >= 0) + { + initSpeed(); + } + } + + private void initSpeed() + { + if (this.type == TweenAction.MOVE_CURVED || this.type == TweenAction.MOVE_CURVED_LOCAL) + { + this.time = this._optional.path.distance / this.speed; + } + else if (this.type == TweenAction.MOVE_SPLINE || this.type == TweenAction.MOVE_SPLINE_LOCAL) + { + this.time = this._optional.spline.distance / this.speed; + } + else + { + this.time = (this.to - this.from).magnitude / this.speed; + } + } + + public static float val; + public static float dt; + public static Vector3 newVect; + + /** + * If you need a tween to happen immediately instead of waiting for the next Update call, you can force it with this method + * + * @method updateNow + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 0f ).updateNow(); + */ + public LTDescr updateNow() + { + updateInternal(); + return this; + } + + public bool updateInternal() + { + + float directionLocal = this.direction; + if (this.usesNormalDt) + { + dt = LeanTween.dtActual; + } + else if (this.useEstimatedTime) + { + dt = LeanTween.dtEstimated; + } + else if (this.useFrames) + { + dt = this.optional.initFrameCount == 0 ? 0 : 1; + this.optional.initFrameCount = Time.frameCount; + } + else if (this.useManualTime) + { + dt = LeanTween.dtManual; + } + + // Debug.Log ("tween:" + this+ " dt:"+dt); + if (this.delay <= 0f && directionLocal != 0f) + { + if (trans == null) + return true; + + // initialize if has not done so yet + if (!this.hasInitiliazed) + this.init(); + + dt = dt * directionLocal; + this.passed += dt; + + this.passed = Mathf.Clamp(this.passed, 0f, this.time); + + this.ratioPassed = (this.passed / this.time); // need to clamp when finished so it will finish at the exact spot and not overshoot + + this.easeInternal(); + + if (this.hasUpdateCallback) + this._optional.callOnUpdate(val, this.ratioPassed); + + bool isTweenFinished = directionLocal > 0f ? this.passed >= this.time : this.passed <= 0f; + // Debug.Log("lt "+this+" dt:"+dt+" fin:"+isTweenFinished); + if (isTweenFinished) + { // increment or flip tween + this.loopCount--; + if (this.loopType == LeanTweenType.pingPong) + { + this.direction = 0.0f - directionLocal; + } + else + { + this.passed = Mathf.Epsilon; + } + + isTweenFinished = this.loopCount == 0 || this.loopType == LeanTweenType.once; // only return true if it is fully complete + + if (isTweenFinished == false && this.onCompleteOnRepeat && this.hasExtraOnCompletes) + callOnCompletes(); // this only gets called if onCompleteOnRepeat is set to true, otherwise LeanTween class takes care of calling it + + return isTweenFinished; + } + } + else + { + this.delay -= dt; + } + + return false; + } + + public void callOnCompletes() + { + if (this.type == TweenAction.GUI_ROTATE) + this._optional.ltRect.rotateFinished = true; + + if (this.type == TweenAction.DELAYED_SOUND) + { + AudioSource.PlayClipAtPoint((AudioClip)this._optional.onCompleteParam, this.to, this.from.x); + } + if (this._optional.onComplete != null) + { + this._optional.onComplete(); + } + else if (this._optional.onCompleteObject != null) + { + this._optional.onCompleteObject(this._optional.onCompleteParam); + } + } + + // Helper Methods + + public LTDescr setFromColor(Color col) + { + this.from = new Vector3(0.0f, col.a, 0.0f); + this.diff = new Vector3(1.0f, 0.0f, 0.0f); + this._optional.axis = new Vector3(col.r, col.g, col.b); + return this; + } + + private static void alphaRecursive(Transform transform, float val, bool useRecursion = true) + { + Renderer renderer = transform.gameObject.GetComponent(); + if (renderer != null) + { + foreach (Material mat in renderer.materials) + { + if (mat.HasProperty("_Color")) + { + mat.color = new Color(mat.color.r, mat.color.g, mat.color.b, val); + } + else if (mat.HasProperty("_TintColor")) + { + Color col = mat.GetColor("_TintColor"); + mat.SetColor("_TintColor", new Color(col.r, col.g, col.b, val)); + } + } + } + if (useRecursion && transform.childCount > 0) + { + foreach (Transform child in transform) + { + alphaRecursive(child, val); + } + } + } + + private static void colorRecursive(Transform transform, Color toColor, bool useRecursion = true) + { + Renderer ren = transform.gameObject.GetComponent(); + if (ren != null) + { + foreach (Material mat in ren.materials) + { + mat.color = toColor; + } + } + if (useRecursion && transform.childCount > 0) + { + foreach (Transform child in transform) + { + colorRecursive(child, toColor); + } + } + } + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 + + private static void alphaRecursive(RectTransform rectTransform, float val, int recursiveLevel = 0) + { + if (rectTransform.childCount > 0) + { + foreach (RectTransform child in rectTransform) + { + UnityEngine.UI.MaskableGraphic uiImage = child.GetComponent(); + if (uiImage != null) + { + Color c = uiImage.color; c.a = val; uiImage.color = c; + } + else + { + uiImage = child.GetComponent(); + if (uiImage != null) + { + Color c = uiImage.color; c.a = val; uiImage.color = c; + } + } + + alphaRecursive(child, val, recursiveLevel + 1); + } + } + } + + private static void alphaRecursiveSprite(Transform transform, float val) + { + if (transform.childCount > 0) + { + foreach (Transform child in transform) + { + SpriteRenderer ren = child.GetComponent(); + if (ren != null) + ren.color = new Color(ren.color.r, ren.color.g, ren.color.b, val); + alphaRecursiveSprite(child, val); + } + } + } + + private static void colorRecursiveSprite(Transform transform, Color toColor) + { + if (transform.childCount > 0) + { + foreach (Transform child in transform) + { + SpriteRenderer ren = transform.gameObject.GetComponent(); + if (ren != null) + ren.color = toColor; + colorRecursiveSprite(child, toColor); + } + } + } + + private static void colorRecursive(RectTransform rectTransform, Color toColor) + { + + if (rectTransform.childCount > 0) + { + foreach (RectTransform child in rectTransform) + { + UnityEngine.UI.MaskableGraphic uiImage = child.GetComponent(); + if (uiImage != null) + { + uiImage.color = toColor; + } + else + { + uiImage = child.GetComponent(); + if (uiImage != null) + uiImage.color = toColor; + } + colorRecursive(child, toColor); + } + } + } + + private static void textAlphaChildrenRecursive(Transform trans, float val, bool useRecursion = true) + { + + if (useRecursion && trans.childCount > 0) + { + foreach (Transform child in trans) + { + UnityEngine.UI.Text uiText = child.GetComponent(); + if (uiText != null) + { + Color c = uiText.color; + c.a = val; + uiText.color = c; + } + textAlphaChildrenRecursive(child, val); + } + } + } + + private static void textAlphaRecursive(Transform trans, float val, bool useRecursion = true) + { + UnityEngine.UI.Text uiText = trans.GetComponent(); + if (uiText != null) + { + Color c = uiText.color; + c.a = val; + uiText.color = c; + } + if (useRecursion && trans.childCount > 0) + { + foreach (Transform child in trans) + { + textAlphaRecursive(child, val); + } + } + } + + private static void textColorRecursive(Transform trans, Color toColor) + { + if (trans.childCount > 0) + { + foreach (Transform child in trans) + { + UnityEngine.UI.Text uiText = child.GetComponent(); + if (uiText != null) + { + uiText.color = toColor; + } + textColorRecursive(child, toColor); + } + } + } +#endif + + private static Color tweenColor(LTDescr tween, float val) + { + Vector3 diff3 = tween._optional.point - tween._optional.axis; + float diffAlpha = tween.to.y - tween.from.y; + return new Color(tween._optional.axis.x + diff3.x * val, tween._optional.axis.y + diff3.y * val, tween._optional.axis.z + diff3.z * val, tween.from.y + diffAlpha * val); + } + + /** + * Pause a tween + * + * @method pause + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public LTDescr pause() + { + if (this.direction != 0.0f) + { // check if tween is already paused + this.directionLast = this.direction; + this.direction = 0.0f; + } + + return this; + } + + /** + * Resume a paused tween + * + * @method resume + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public LTDescr resume() + { + this.direction = this.directionLast; + + return this; + } + + /** + * Set Axis optional axis for tweens where it is relevant + * + * @method setAxis + * @param {Vector3} axis either the tween rotates around, or the direction it faces in the case of setOrientToPath + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.move( ltLogo, path, 1.0f ).setEase(LeanTweenType.easeOutQuad).setOrientToPath(true).setAxis(Vector3.forward); + */ + public LTDescr setAxis(Vector3 axis) + { + this._optional.axis = axis; + return this; + } + + /** + * Delay the start of a tween + * + * @method setDelay + * @param {float} float time The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setDelay( 1.5f ); + */ + public LTDescr setDelay(float delay) + { + this.delay = delay; + + return this; + } + + /** + * Set the type of easing used for the tween.
+ * + * + * @method setEase + * @param {LeanTweenType} easeType:LeanTweenType the easing type to use + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setEase( LeanTweenType.easeInBounce ); + */ + public LTDescr setEase(LeanTweenType easeType) + { + + switch (easeType) + { + case LeanTweenType.linear: + setEaseLinear(); break; + case LeanTweenType.easeOutQuad: + setEaseOutQuad(); break; + case LeanTweenType.easeInQuad: + setEaseInQuad(); break; + case LeanTweenType.easeInOutQuad: + setEaseInOutQuad(); break; + case LeanTweenType.easeInCubic: + setEaseInCubic(); break; + case LeanTweenType.easeOutCubic: + setEaseOutCubic(); break; + case LeanTweenType.easeInOutCubic: + setEaseInOutCubic(); break; + case LeanTweenType.easeInQuart: + setEaseInQuart(); break; + case LeanTweenType.easeOutQuart: + setEaseOutQuart(); break; + case LeanTweenType.easeInOutQuart: + setEaseInOutQuart(); break; + case LeanTweenType.easeInQuint: + setEaseInQuint(); break; + case LeanTweenType.easeOutQuint: + setEaseOutQuint(); break; + case LeanTweenType.easeInOutQuint: + setEaseInOutQuint(); break; + case LeanTweenType.easeInSine: + setEaseInSine(); break; + case LeanTweenType.easeOutSine: + setEaseOutSine(); break; + case LeanTweenType.easeInOutSine: + setEaseInOutSine(); break; + case LeanTweenType.easeInExpo: + setEaseInExpo(); break; + case LeanTweenType.easeOutExpo: + setEaseOutExpo(); break; + case LeanTweenType.easeInOutExpo: + setEaseInOutExpo(); break; + case LeanTweenType.easeInCirc: + setEaseInCirc(); break; + case LeanTweenType.easeOutCirc: + setEaseOutCirc(); break; + case LeanTweenType.easeInOutCirc: + setEaseInOutCirc(); break; + case LeanTweenType.easeInBounce: + setEaseInBounce(); break; + case LeanTweenType.easeOutBounce: + setEaseOutBounce(); break; + case LeanTweenType.easeInOutBounce: + setEaseInOutBounce(); break; + case LeanTweenType.easeInBack: + setEaseInBack(); break; + case LeanTweenType.easeOutBack: + setEaseOutBack(); break; + case LeanTweenType.easeInOutBack: + setEaseInOutBack(); break; + case LeanTweenType.easeInElastic: + setEaseInElastic(); break; + case LeanTweenType.easeOutElastic: + setEaseOutElastic(); break; + case LeanTweenType.easeInOutElastic: + setEaseInOutElastic(); break; + case LeanTweenType.punch: + setEasePunch(); break; + case LeanTweenType.easeShake: + setEaseShake(); break; + case LeanTweenType.easeSpring: + setEaseSpring(); break; + default: + setEaseLinear(); break; + } + + return this; + } + + public LTDescr setEaseLinear() { this.easeType = LeanTweenType.linear; this.easeMethod = this.easeLinear; return this; } + + public LTDescr setEaseSpring() { this.easeType = LeanTweenType.easeSpring; this.easeMethod = this.easeSpring; return this; } + + public LTDescr setEaseInQuad() { this.easeType = LeanTweenType.easeInQuad; this.easeMethod = this.easeInQuad; return this; } + + public LTDescr setEaseOutQuad() { this.easeType = LeanTweenType.easeOutQuad; this.easeMethod = this.easeOutQuad; return this; } + + public LTDescr setEaseInOutQuad() { this.easeType = LeanTweenType.easeInOutQuad; this.easeMethod = this.easeInOutQuad; return this; } + + public LTDescr setEaseInCubic() { this.easeType = LeanTweenType.easeInCubic; this.easeMethod = this.easeInCubic; return this; } + + public LTDescr setEaseOutCubic() { this.easeType = LeanTweenType.easeOutCubic; this.easeMethod = this.easeOutCubic; return this; } + + public LTDescr setEaseInOutCubic() { this.easeType = LeanTweenType.easeInOutCubic; this.easeMethod = this.easeInOutCubic; return this; } + + public LTDescr setEaseInQuart() { this.easeType = LeanTweenType.easeInQuart; this.easeMethod = this.easeInQuart; return this; } + + public LTDescr setEaseOutQuart() { this.easeType = LeanTweenType.easeOutQuart; this.easeMethod = this.easeOutQuart; return this; } + + public LTDescr setEaseInOutQuart() { this.easeType = LeanTweenType.easeInOutQuart; this.easeMethod = this.easeInOutQuart; return this; } + + public LTDescr setEaseInQuint() { this.easeType = LeanTweenType.easeInQuint; this.easeMethod = this.easeInQuint; return this; } + + public LTDescr setEaseOutQuint() { this.easeType = LeanTweenType.easeOutQuint; this.easeMethod = this.easeOutQuint; return this; } + + public LTDescr setEaseInOutQuint() { this.easeType = LeanTweenType.easeInOutQuint; this.easeMethod = this.easeInOutQuint; return this; } + + public LTDescr setEaseInSine() { this.easeType = LeanTweenType.easeInSine; this.easeMethod = this.easeInSine; return this; } + + public LTDescr setEaseOutSine() { this.easeType = LeanTweenType.easeOutSine; this.easeMethod = this.easeOutSine; return this; } + + public LTDescr setEaseInOutSine() { this.easeType = LeanTweenType.easeInOutSine; this.easeMethod = this.easeInOutSine; return this; } + + public LTDescr setEaseInExpo() { this.easeType = LeanTweenType.easeInExpo; this.easeMethod = this.easeInExpo; return this; } + + public LTDescr setEaseOutExpo() { this.easeType = LeanTweenType.easeOutExpo; this.easeMethod = this.easeOutExpo; return this; } + + public LTDescr setEaseInOutExpo() { this.easeType = LeanTweenType.easeInOutExpo; this.easeMethod = this.easeInOutExpo; return this; } + + public LTDescr setEaseInCirc() { this.easeType = LeanTweenType.easeInCirc; this.easeMethod = this.easeInCirc; return this; } + + public LTDescr setEaseOutCirc() { this.easeType = LeanTweenType.easeOutCirc; this.easeMethod = this.easeOutCirc; return this; } + + public LTDescr setEaseInOutCirc() { this.easeType = LeanTweenType.easeInOutCirc; this.easeMethod = this.easeInOutCirc; return this; } + + public LTDescr setEaseInBounce() { this.easeType = LeanTweenType.easeInBounce; this.easeMethod = this.easeInBounce; return this; } + + public LTDescr setEaseOutBounce() { this.easeType = LeanTweenType.easeOutBounce; this.easeMethod = this.easeOutBounce; return this; } + + public LTDescr setEaseInOutBounce() { this.easeType = LeanTweenType.easeInOutBounce; this.easeMethod = this.easeInOutBounce; return this; } + + public LTDescr setEaseInBack() { this.easeType = LeanTweenType.easeInBack; this.easeMethod = this.easeInBack; return this; } + + public LTDescr setEaseOutBack() { this.easeType = LeanTweenType.easeOutBack; this.easeMethod = this.easeOutBack; return this; } + + public LTDescr setEaseInOutBack() { this.easeType = LeanTweenType.easeInOutBack; this.easeMethod = this.easeInOutBack; return this; } + + public LTDescr setEaseInElastic() { this.easeType = LeanTweenType.easeInElastic; this.easeMethod = this.easeInElastic; return this; } + + public LTDescr setEaseOutElastic() { this.easeType = LeanTweenType.easeOutElastic; this.easeMethod = this.easeOutElastic; return this; } + + public LTDescr setEaseInOutElastic() { this.easeType = LeanTweenType.easeInOutElastic; this.easeMethod = this.easeInOutElastic; return this; } + + public LTDescr setEasePunch() { this._optional.animationCurve = LeanTween.punch; this.toInternal.x = this.from.x + this.to.x; this.easeMethod = this.tweenOnCurve; return this; } + + public LTDescr setEaseShake() { this._optional.animationCurve = LeanTween.shake; this.toInternal.x = this.from.x + this.to.x; this.easeMethod = this.tweenOnCurve; return this; } + + private Vector3 tweenOnCurve() + { + return new Vector3(this.from.x + (this.diff.x) * this._optional.animationCurve.Evaluate(ratioPassed), + this.from.y + (this.diff.y) * this._optional.animationCurve.Evaluate(ratioPassed), + this.from.z + (this.diff.z) * this._optional.animationCurve.Evaluate(ratioPassed)); + } + + // Vector3 Ease Methods + + private Vector3 easeInOutQuad() + { + val = this.ratioPassed * 2f; + + if (val < 1f) + { + val = val * val; + return new Vector3(this.diffDiv2.x * val + this.from.x, this.diffDiv2.y * val + this.from.y, this.diffDiv2.z * val + this.from.z); + } + val = (1f - val) * (val - 3f) + 1f; + return new Vector3(this.diffDiv2.x * val + this.from.x, this.diffDiv2.y * val + this.from.y, this.diffDiv2.z * val + this.from.z); + } + + private Vector3 easeInQuad() + { + val = ratioPassed * ratioPassed; + return new Vector3(this.diff.x * val + this.from.x, this.diff.y * val + this.from.y, this.diff.z * val + this.from.z); + } + + private Vector3 easeOutQuad() + { + val = this.ratioPassed; + val = -val * (val - 2f); + return (this.diff * val + this.from); + } + + private Vector3 easeLinear() + { + val = this.ratioPassed; + return new Vector3(this.from.x + this.diff.x * val, this.from.y + this.diff.y * val, this.from.z + this.diff.z * val); + } + + private Vector3 easeSpring() + { + val = Mathf.Clamp01(this.ratioPassed); + val = (Mathf.Sin(val * Mathf.PI * (0.2f + 2.5f * val * val * val)) * Mathf.Pow(1f - val, 2.2f) + val) * (1f + (1.2f * (1f - val))); + return this.from + this.diff * val; + } + + private Vector3 easeInCubic() + { + val = this.ratioPassed * this.ratioPassed * this.ratioPassed; + return new Vector3(this.diff.x * val + this.from.x, this.diff.y * val + this.from.y, this.diff.z * val + this.from.z); + } + + private Vector3 easeOutCubic() + { + val = this.ratioPassed - 1f; + val = (val * val * val + 1); + return new Vector3(this.diff.x * val + this.from.x, this.diff.y * val + this.from.y, this.diff.z * val + this.from.z); + } + + private Vector3 easeInOutCubic() + { + val = this.ratioPassed * 2f; + if (val < 1f) + { + val = val * val * val; + return new Vector3(this.diffDiv2.x * val + this.from.x, this.diffDiv2.y * val + this.from.y, this.diffDiv2.z * val + this.from.z); + } + val -= 2f; + val = val * val * val + 2f; + return new Vector3(this.diffDiv2.x * val + this.from.x, this.diffDiv2.y * val + this.from.y, this.diffDiv2.z * val + this.from.z); + } + + private Vector3 easeInQuart() + { + val = this.ratioPassed * this.ratioPassed * this.ratioPassed * this.ratioPassed; + return diff * val + this.from; + } + + private Vector3 easeOutQuart() + { + val = this.ratioPassed - 1f; + val = -(val * val * val * val - 1); + return new Vector3(this.diff.x * val + this.from.x, this.diff.y * val + this.from.y, this.diff.z * val + this.from.z); + } + + private Vector3 easeInOutQuart() + { + val = this.ratioPassed * 2f; + if (val < 1f) + { + val = val * val * val * val; + return new Vector3(this.diffDiv2.x * val + this.from.x, this.diffDiv2.y * val + this.from.y, this.diffDiv2.z * val + this.from.z); + } + val -= 2f; + // val = (val * val * val * val - 2f); + return -this.diffDiv2 * (val * val * val * val - 2f) + this.from; + } + + private Vector3 easeInQuint() + { + val = this.ratioPassed; + val = val * val * val * val * val; + return new Vector3(this.diff.x * val + this.from.x, this.diff.y * val + this.from.y, this.diff.z * val + this.from.z); + } + + private Vector3 easeOutQuint() + { + val = this.ratioPassed - 1f; + val = (val * val * val * val * val + 1f); + return new Vector3(this.diff.x * val + this.from.x, this.diff.y * val + this.from.y, this.diff.z * val + this.from.z); + } + + private Vector3 easeInOutQuint() + { + val = this.ratioPassed * 2f; + if (val < 1f) + { + val = val * val * val * val * val; + return new Vector3(this.diffDiv2.x * val + this.from.x, this.diffDiv2.y * val + this.from.y, this.diffDiv2.z * val + this.from.z); + } + val -= 2f; + val = (val * val * val * val * val + 2f); + return new Vector3(this.diffDiv2.x * val + this.from.x, this.diffDiv2.y * val + this.from.y, this.diffDiv2.z * val + this.from.z); + } + + private Vector3 easeInSine() + { + val = -Mathf.Cos(this.ratioPassed * LeanTween.PI_DIV2); + return new Vector3(this.diff.x * val + this.diff.x + this.from.x, this.diff.y * val + this.diff.y + this.from.y, this.diff.z * val + this.diff.z + this.from.z); + } + + private Vector3 easeOutSine() + { + val = Mathf.Sin(this.ratioPassed * LeanTween.PI_DIV2); + return new Vector3(this.diff.x * val + this.from.x, this.diff.y * val + this.from.y, this.diff.z * val + this.from.z); + } + + private Vector3 easeInOutSine() + { + val = -(Mathf.Cos(Mathf.PI * this.ratioPassed) - 1f); + return new Vector3(this.diffDiv2.x * val + this.from.x, this.diffDiv2.y * val + this.from.y, this.diffDiv2.z * val + this.from.z); + } + + private Vector3 easeInExpo() + { + val = Mathf.Pow(2f, 10f * (this.ratioPassed - 1f)); + return new Vector3(this.diff.x * val + this.from.x, this.diff.y * val + this.from.y, this.diff.z * val + this.from.z); + } + + private Vector3 easeOutExpo() + { + val = (-Mathf.Pow(2f, -10f * this.ratioPassed) + 1f); + return new Vector3(this.diff.x * val + this.from.x, this.diff.y * val + this.from.y, this.diff.z * val + this.from.z); + } + + private Vector3 easeInOutExpo() + { + val = this.ratioPassed * 2f; + if (val < 1) return this.diffDiv2 * Mathf.Pow(2, 10 * (val - 1)) + this.from; + val--; + return this.diffDiv2 * (-Mathf.Pow(2, -10 * val) + 2) + this.from; + } + + private Vector3 easeInCirc() + { + val = -(Mathf.Sqrt(1f - this.ratioPassed * this.ratioPassed) - 1f); + return new Vector3(this.diff.x * val + this.from.x, this.diff.y * val + this.from.y, this.diff.z * val + this.from.z); + } + + private Vector3 easeOutCirc() + { + val = this.ratioPassed - 1f; + val = Mathf.Sqrt(1f - val * val); + + return new Vector3(this.diff.x * val + this.from.x, this.diff.y * val + this.from.y, this.diff.z * val + this.from.z); + } + + private Vector3 easeInOutCirc() + { + val = this.ratioPassed * 2f; + if (val < 1f) + { + val = -(Mathf.Sqrt(1f - val * val) - 1f); + return new Vector3(this.diffDiv2.x * val + this.from.x, this.diffDiv2.y * val + this.from.y, this.diffDiv2.z * val + this.from.z); + } + val -= 2f; + val = (Mathf.Sqrt(1f - val * val) + 1f); + return new Vector3(this.diffDiv2.x * val + this.from.x, this.diffDiv2.y * val + this.from.y, this.diffDiv2.z * val + this.from.z); + } + + private Vector3 easeInBounce() + { + val = this.ratioPassed; + val = 1f - val; + return new Vector3(this.diff.x - LeanTween.easeOutBounce(0, this.diff.x, val) + this.from.x, + this.diff.y - LeanTween.easeOutBounce(0, this.diff.y, val) + this.from.y, + this.diff.z - LeanTween.easeOutBounce(0, this.diff.z, val) + this.from.z); + } + + private Vector3 easeOutBounce() + { + val = ratioPassed; + float valM, valN; // bounce values + if (val < (valM = 1 - 1.75f * this.overshoot / 2.75f)) + { + val = 1 / valM / valM * val * val; + } + else if (val < (valN = 1 - .75f * this.overshoot / 2.75f)) + { + val -= (valM + valN) / 2; + // first bounce, height: 1/4 + val = 7.5625f * val * val + 1 - .25f * this.overshoot * this.overshoot; + } + else if (val < (valM = 1 - .25f * this.overshoot / 2.75f)) + { + val -= (valM + valN) / 2; + // second bounce, height: 1/16 + val = 7.5625f * val * val + 1 - .0625f * this.overshoot * this.overshoot; + } + else + { // valN = 1 + val -= (valM + 1) / 2; + // third bounce, height: 1/64 + val = 7.5625f * val * val + 1 - .015625f * this.overshoot * this.overshoot; + } + return this.diff * val + this.from; + } + + private Vector3 easeInOutBounce() + { + val = this.ratioPassed * 2f; + if (val < 1f) + { + return new Vector3(LeanTween.easeInBounce(0, this.diff.x, val) * 0.5f + this.from.x, + LeanTween.easeInBounce(0, this.diff.y, val) * 0.5f + this.from.y, + LeanTween.easeInBounce(0, this.diff.z, val) * 0.5f + this.from.z); + } + else + { + val = val - 1f; + return new Vector3(LeanTween.easeOutBounce(0, this.diff.x, val) * 0.5f + this.diffDiv2.x + this.from.x, + LeanTween.easeOutBounce(0, this.diff.y, val) * 0.5f + this.diffDiv2.y + this.from.y, + LeanTween.easeOutBounce(0, this.diff.z, val) * 0.5f + this.diffDiv2.z + this.from.z); + } + } + + private Vector3 easeInBack() + { + val = this.ratioPassed; + val /= 1; + float s = 1.70158f * this.overshoot; + return this.diff * (val) * val * ((s + 1) * val - s) + this.from; + } + + private Vector3 easeOutBack() + { + float s = 1.70158f * this.overshoot; + val = (this.ratioPassed / 1) - 1; + val = ((val) * val * ((s + 1) * val + s) + 1); + return this.diff * val + this.from; + } + + private Vector3 easeInOutBack() + { + float s = 1.70158f * this.overshoot; + val = this.ratioPassed * 2f; + if ((val) < 1) + { + s *= (1.525f) * overshoot; + return this.diffDiv2 * (val * val * (((s) + 1) * val - s)) + this.from; + } + val -= 2; + s *= (1.525f) * overshoot; + val = ((val) * val * (((s) + 1) * val + s) + 2); + return this.diffDiv2 * val + this.from; + } + + private Vector3 easeInElastic() + { + return new Vector3(LeanTween.easeInElastic(this.from.x, this.to.x, this.ratioPassed, this.overshoot, this.period), + LeanTween.easeInElastic(this.from.y, this.to.y, this.ratioPassed, this.overshoot, this.period), + LeanTween.easeInElastic(this.from.z, this.to.z, this.ratioPassed, this.overshoot, this.period)); + } + + private Vector3 easeOutElastic() + { + return new Vector3(LeanTween.easeOutElastic(this.from.x, this.to.x, this.ratioPassed, this.overshoot, this.period), + LeanTween.easeOutElastic(this.from.y, this.to.y, this.ratioPassed, this.overshoot, this.period), + LeanTween.easeOutElastic(this.from.z, this.to.z, this.ratioPassed, this.overshoot, this.period)); + } + + private Vector3 easeInOutElastic() + { + return new Vector3(LeanTween.easeInOutElastic(this.from.x, this.to.x, this.ratioPassed, this.overshoot, this.period), + LeanTween.easeInOutElastic(this.from.y, this.to.y, this.ratioPassed, this.overshoot, this.period), + LeanTween.easeInOutElastic(this.from.z, this.to.z, this.ratioPassed, this.overshoot, this.period)); + } + + /** + * Set how far past a tween will overshoot for certain ease types (compatible: easeInBack, easeInOutBack, easeOutBack, easeOutElastic, easeInElastic, easeInOutElastic).
+ * @method setOvershoot + * @param {float} overshoot:float how far past the destination it will go before settling in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setEase( LeanTweenType.easeOutBack ).setOvershoot(2f); + */ + public LTDescr setOvershoot(float overshoot) + { + this.overshoot = overshoot; + return this; + } + + /** + * Set how short the iterations are for certain ease types (compatible: easeOutElastic, easeInElastic, easeInOutElastic).
+ * @method setPeriod + * @param {float} period:float how short the iterations are that the tween will animate at (default 0.3f) + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setEase( LeanTweenType.easeOutElastic ).setPeriod(0.3f); + */ + public LTDescr setPeriod(float period) + { + this.period = period; + return this; + } + + /** + * Set how large the effect is for certain ease types (compatible: punch, shake, animation curves).
+ * @method setScale + * @param {float} scale:float how much the ease will be multiplied by (default 1f) + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setEase( LeanTweenType.punch ).setScale(2f); + */ + public LTDescr setScale(float scale) + { + this.scale = scale; + return this; + } + + /** + * Set the type of easing used for the tween with a custom curve.
+ * @method setEase (AnimationCurve) + * @param {AnimationCurve} easeDefinition:AnimationCurve an AnimationCure that describes the type of easing you want, this is great for when you want a unique type of movement + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setEase( LeanTweenType.easeInBounce ); + */ + public LTDescr setEase(AnimationCurve easeCurve) + { + this._optional.animationCurve = easeCurve; + this.easeMethod = this.tweenOnCurve; + this.easeType = LeanTweenType.animationCurve; + return this; + } + + /** + * Set the end that the GameObject is tweening towards + * @method setTo + * @param {Vector3} to:Vector3 point at which you want the tween to reach + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LTDescr descr = LeanTween.move( cube, Vector3.up, new Vector3(1f,3f,0f), 1.0f ).setEase( LeanTweenType.easeInOutBounce );
+ * // Later your want to change your destination or your destiation is constantly moving
+ * descr.setTo( new Vector3(5f,10f,3f) );
+ */ + public LTDescr setTo(Vector3 to) + { + if (this.hasInitiliazed) + { + this.to = to; + this.diff = to - this.from; + } + else + { + this.to = to; + } + + return this; + } + + public LTDescr setTo(Transform to) + { + this._optional.toTrans = to; + return this; + } + + /** + * Set the beginning of the tween + * @method setFrom + * @param {Vector3} from:Vector3 the point you would like the tween to start at + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LTDescr descr = LeanTween.move( cube, Vector3.up, new Vector3(1f,3f,0f), 1.0f ).setFrom( new Vector3(5f,10f,3f) );
+ */ + public LTDescr setFrom(Vector3 from) + { + if (this.trans) + { + this.init(); + } + this.from = from; + // this.hasInitiliazed = true; // this is set, so that the "from" value isn't overwritten later on when the tween starts + this.diff = this.to - this.from; + this.diffDiv2 = this.diff * 0.5f; + return this; + } + + public LTDescr setFrom(float from) + { + return setFrom(new Vector3(from, 0f, 0f)); + } + + public LTDescr setDiff(Vector3 diff) + { + this.diff = diff; + return this; + } + + public LTDescr setHasInitialized(bool has) + { + this.hasInitiliazed = has; + return this; + } + + public LTDescr setId(uint id, uint global_counter) + { + this._id = id; + this.counter = global_counter; + // Debug.Log("Global counter:"+global_counter); + return this; + } + + /** + * Set the point of time the tween will start in + * @method setPassed + * @param {float} passedTime:float the length of time in seconds the tween will start in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * int tweenId = LeanTween.moveX(gameObject, 5f, 2.0f ).id;
+ * // Later
+ * LTDescr descr = description( tweenId );
+ * descr.setPassed( 1f );
+ */ + public LTDescr setPassed(float passed) + { + this.passed = passed; + return this; + } + + /** + * Set the finish time of the tween + * @method setTime + * @param {float} finishTime:float the length of time in seconds you wish the tween to complete in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * int tweenId = LeanTween.moveX(gameObject, 5f, 2.0f ).id;
+ * // Later
+ * LTDescr descr = description( tweenId );
+ * descr.setTime( 1f );
+ */ + public LTDescr setTime(float time) + { + float passedTimeRatio = this.passed / this.time; + this.passed = time * passedTimeRatio; + this.time = time; + return this; + } + + /** + * Set the finish time of the tween + * @method setSpeed + * @param {float} speed:float the speed in unity units per second you wish the object to travel (overrides the given time) + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveLocalZ( gameObject, 10f, 1f).setSpeed(0.2f) // the given time is ignored when speed is set
+ */ + public LTDescr setSpeed(float speed) + { + this.speed = speed; + if (this.hasInitiliazed) + initSpeed(); + return this; + } + + /** + * Set the tween to repeat a number of times. + * @method setRepeat + * @param {int} repeatNum:int the number of times to repeat the tween. -1 to repeat infinite times + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setRepeat( 10 ).setLoopPingPong(); + */ + public LTDescr setRepeat(int repeat) + { + this.loopCount = repeat; + if ((repeat > 1 && this.loopType == LeanTweenType.once) || (repeat < 0 && this.loopType == LeanTweenType.once)) + { + this.loopType = LeanTweenType.clamp; + } + if (this.type == TweenAction.CALLBACK || this.type == TweenAction.CALLBACK_COLOR) + { + this.setOnCompleteOnRepeat(true); + } + return this; + } + + public LTDescr setLoopType(LeanTweenType loopType) + { + this.loopType = loopType; + return this; + } + + public LTDescr setUseEstimatedTime(bool useEstimatedTime) + { + this.useEstimatedTime = useEstimatedTime; + this.usesNormalDt = false; + return this; + } + + /** + * Set ignore time scale when tweening an object when you want the animation to be time-scale independent (ignores the Time.timeScale value). Great for pause screens, when you want all other action to be stopped (or slowed down) + * @method setIgnoreTimeScale + * @param {bool} useUnScaledTime:bool whether to use the unscaled time or not + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setRepeat( 2 ).setIgnoreTimeScale( true ); + */ + public LTDescr setIgnoreTimeScale(bool useUnScaledTime) + { + this.useEstimatedTime = useUnScaledTime; + this.usesNormalDt = false; + return this; + } + + /** + * Use frames when tweening an object, when you don't want the animation to be time-frame independent... + * @method setUseFrames + * @param {bool} useFrames:bool whether to use estimated time or not + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setRepeat( 2 ).setUseFrames( true ); + */ + public LTDescr setUseFrames(bool useFrames) + { + this.useFrames = useFrames; + this.usesNormalDt = false; + return this; + } + + public LTDescr setUseManualTime(bool useManualTime) + { + this.useManualTime = useManualTime; + this.usesNormalDt = false; + return this; + } + + public LTDescr setLoopCount(int loopCount) + { + this.loopType = LeanTweenType.clamp; + this.loopCount = loopCount; + return this; + } + + /** + * No looping involved, just run once (the default) + * @method setLoopOnce + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setLoopOnce(); + */ + public LTDescr setLoopOnce() { this.loopType = LeanTweenType.once; return this; } + + /** + * When the animation gets to the end it starts back at where it began + * @method setLoopClamp + * @param {int} loops:int (defaults to -1) how many times you want the loop to happen (-1 for an infinite number of times) + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setLoopClamp( 2 ); + */ + public LTDescr setLoopClamp() + { + this.loopType = LeanTweenType.clamp; + if (this.loopCount == 0) + this.loopCount = -1; + return this; + } + public LTDescr setLoopClamp(int loops) + { + this.loopCount = loops; + return this; + } + + /** + * When the animation gets to the end it then tweens back to where it started (and on, and on) + * @method setLoopPingPong + * @param {int} loops:int (defaults to -1) how many times you want the loop to happen in both directions (-1 for an infinite number of times). Passing a value of 1 will cause the object to go towards and back from it's destination once. + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setLoopPingPong( 2 ); + */ + public LTDescr setLoopPingPong() + { + this.loopType = LeanTweenType.pingPong; + if (this.loopCount == 0) + this.loopCount = -1; + return this; + } + public LTDescr setLoopPingPong(int loops) + { + this.loopType = LeanTweenType.pingPong; + this.loopCount = loops == -1 ? loops : loops * 2; + return this; + } + + /** + * Have a method called when the tween finishes + * @method setOnComplete + * @param {Action} onComplete:Action the method that should be called when the tween is finished ex: tweenFinished(){ } + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setOnComplete( tweenFinished ); + */ + public LTDescr setOnComplete(Action onComplete) + { + this._optional.onComplete = onComplete; + this.hasExtraOnCompletes = true; + return this; + } + + /** + * Have a method called when the tween finishes + * @method setOnComplete (object) + * @param {Action} onComplete:Action the method that should be called when the tween is finished ex: tweenFinished( object myObj ){ } + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * object tweenFinishedObj = "hi" as object; + * LeanTween.moveX(gameObject, 5f, 2.0f ).setOnComplete( tweenFinished, tweenFinishedObj ); + */ + public LTDescr setOnComplete(Action onComplete) + { + this._optional.onCompleteObject = onComplete; + this.hasExtraOnCompletes = true; + return this; + } + public LTDescr setOnComplete(Action onComplete, object onCompleteParam) + { + this._optional.onCompleteObject = onComplete; + this.hasExtraOnCompletes = true; + if (onCompleteParam != null) + this._optional.onCompleteParam = onCompleteParam; + return this; + } + + /** + * Pass an object to along with the onComplete Function + * @method setOnCompleteParam + * @param {object} onComplete:object an object that + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.delayedCall(1.5f, enterMiniGameStart).setOnCompleteParam( new object[]{""+5} );

+ * void enterMiniGameStart( object val ){
+ *  object[] arr = (object [])val;
+ *  int lvl = int.Parse((string)arr[0]);
+ * }
+ */ + public LTDescr setOnCompleteParam(object onCompleteParam) + { + this._optional.onCompleteParam = onCompleteParam; + this.hasExtraOnCompletes = true; + return this; + } + + + /** + * Have a method called on each frame that the tween is being animated (passes a float value) + * @method setOnUpdate + * @param {Action} onUpdate:Action a method that will be called on every frame with the float value of the tweened object + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setOnUpdate( tweenMoved );
+ *
+ * void tweenMoved( float val ){ }
+ */ + public LTDescr setOnUpdate(Action onUpdate) + { + this._optional.onUpdateFloat = onUpdate; + this.hasUpdateCallback = true; + return this; + } + public LTDescr setOnUpdateRatio(Action onUpdate) + { + this._optional.onUpdateFloatRatio = onUpdate; + this.hasUpdateCallback = true; + return this; + } + + public LTDescr setOnUpdateObject(Action onUpdate) + { + this._optional.onUpdateFloatObject = onUpdate; + this.hasUpdateCallback = true; + return this; + } + public LTDescr setOnUpdateVector2(Action onUpdate) + { + this._optional.onUpdateVector2 = onUpdate; + this.hasUpdateCallback = true; + return this; + } + public LTDescr setOnUpdateVector3(Action onUpdate) + { + this._optional.onUpdateVector3 = onUpdate; + this.hasUpdateCallback = true; + return this; + } + public LTDescr setOnUpdateColor(Action onUpdate) + { + this._optional.onUpdateColor = onUpdate; + this.hasUpdateCallback = true; + return this; + } + public LTDescr setOnUpdateColor(Action onUpdate) + { + this._optional.onUpdateColorObject = onUpdate; + this.hasUpdateCallback = true; + return this; + } + +#if !UNITY_FLASH + + public LTDescr setOnUpdate(Action onUpdate) + { + this._optional.onUpdateColor = onUpdate; + this.hasUpdateCallback = true; + return this; + } + + public LTDescr setOnUpdate(Action onUpdate) + { + this._optional.onUpdateColorObject = onUpdate; + this.hasUpdateCallback = true; + return this; + } + + /** + * Have a method called on each frame that the tween is being animated (passes a float value and a object) + * @method setOnUpdate (object) + * @param {Action} onUpdate:Action a method that will be called on every frame with the float value of the tweened object, and an object of the person's choosing + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setOnUpdate( tweenMoved ).setOnUpdateParam( myObject );
+ *
+ * void tweenMoved( float val, object obj ){ }
+ */ + public LTDescr setOnUpdate(Action onUpdate, object onUpdateParam = null) + { + this._optional.onUpdateFloatObject = onUpdate; + this.hasUpdateCallback = true; + if (onUpdateParam != null) + this._optional.onUpdateParam = onUpdateParam; + return this; + } + + public LTDescr setOnUpdate(Action onUpdate, object onUpdateParam = null) + { + this._optional.onUpdateVector3Object = onUpdate; + this.hasUpdateCallback = true; + if (onUpdateParam != null) + this._optional.onUpdateParam = onUpdateParam; + return this; + } + + public LTDescr setOnUpdate(Action onUpdate, object onUpdateParam = null) + { + this._optional.onUpdateVector2 = onUpdate; + this.hasUpdateCallback = true; + if (onUpdateParam != null) + this._optional.onUpdateParam = onUpdateParam; + return this; + } + + /** + * Have a method called on each frame that the tween is being animated (passes a float value) + * @method setOnUpdate (Vector3) + * @param {Action} onUpdate:Action a method that will be called on every frame with the float value of the tweened object + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setOnUpdate( tweenMoved );
+ *
+ * void tweenMoved( Vector3 val ){ }
+ */ + public LTDescr setOnUpdate(Action onUpdate, object onUpdateParam = null) + { + this._optional.onUpdateVector3 = onUpdate; + this.hasUpdateCallback = true; + if (onUpdateParam != null) + this._optional.onUpdateParam = onUpdateParam; + return this; + } +#endif + + + /** + * Have an object passed along with the onUpdate method + * @method setOnUpdateParam + * @param {object} onUpdateParam:object an object that will be passed along with the onUpdate method + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveX(gameObject, 5f, 2.0f ).setOnUpdate( tweenMoved ).setOnUpdateParam( myObject );
+ *
+ * void tweenMoved( float val, object obj ){ }
+ */ + public LTDescr setOnUpdateParam(object onUpdateParam) + { + this._optional.onUpdateParam = onUpdateParam; + return this; + } + + /** + * While tweening along a curve, set this property to true, to be perpendicalur to the path it is moving upon + * @method setOrientToPath + * @param {bool} doesOrient:bool whether the gameobject will orient to the path it is animating along + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.move( ltLogo, path, 1.0f ).setEase(LeanTweenType.easeOutQuad).setOrientToPath(true).setAxis(Vector3.forward);
+ */ + public LTDescr setOrientToPath(bool doesOrient) + { + if (this.type == TweenAction.MOVE_CURVED || this.type == TweenAction.MOVE_CURVED_LOCAL) + { + if (this._optional.path == null) + this._optional.path = new LTBezierPath(); + this._optional.path.orientToPath = doesOrient; + } + else + { + this._optional.spline.orientToPath = doesOrient; + } + return this; + } + + /** + * While tweening along a curve, set this property to true, to be perpendicalur to the path it is moving upon + * @method setOrientToPath2d + * @param {bool} doesOrient:bool whether the gameobject will orient to the path it is animating along + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.move( ltLogo, path, 1.0f ).setEase(LeanTweenType.easeOutQuad).setOrientToPath2d(true).setAxis(Vector3.forward);
+ */ + public LTDescr setOrientToPath2d(bool doesOrient2d) + { + setOrientToPath(doesOrient2d); + if (this.type == TweenAction.MOVE_CURVED || this.type == TweenAction.MOVE_CURVED_LOCAL) + { + this._optional.path.orientToPath2d = doesOrient2d; + } + else + { + this._optional.spline.orientToPath2d = doesOrient2d; + } + return this; + } + + public LTDescr setRect(LTRect rect) + { + this._optional.ltRect = rect; + return this; + } + + public LTDescr setRect(Rect rect) + { + this._optional.ltRect = new LTRect(rect); + return this; + } + + public LTDescr setPath(LTBezierPath path) + { + this._optional.path = path; + return this; + } + + /** + * Set the point at which the GameObject will be rotated around + * @method setPoint + * @param {Vector3} point:Vector3 point at which you want the object to rotate around (local space) + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.rotateAround( cube, Vector3.up, 360.0f, 1.0f ) .setPoint( new Vector3(1f,0f,0f) ) .setEase( LeanTweenType.easeInOutBounce );
+ */ + public LTDescr setPoint(Vector3 point) + { + this._optional.point = point; + return this; + } + + public LTDescr setDestroyOnComplete(bool doesDestroy) + { + this.destroyOnComplete = doesDestroy; + return this; + } + + public LTDescr setAudio(object audio) + { + this._optional.onCompleteParam = audio; + return this; + } + + /** + * Set the onComplete method to be called at the end of every loop cycle (also applies to the delayedCall method) + * @method setOnCompleteOnRepeat + * @param {bool} isOn:bool does call onComplete on every loop cycle + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.delayedCall(gameObject,0.3f, delayedMethod).setRepeat(4).setOnCompleteOnRepeat(true); + */ + public LTDescr setOnCompleteOnRepeat(bool isOn) + { + this.onCompleteOnRepeat = isOn; + return this; + } + + /** + * Set the onComplete method to be called at the beginning of the tween (it will still be called when it is completed as well) + * @method setOnCompleteOnStart + * @param {bool} isOn:bool does call onComplete at the start of the tween + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.delayedCall(gameObject, 2f, ()=>{
// Flash an object 5 times + *  LeanTween.alpha(gameObject, 0f, 1f);
+ *  LeanTween.alpha(gameObject, 1f, 0f).setDelay(1f);
+ * }).setOnCompleteOnStart(true).setRepeat(5);
+ */ + public LTDescr setOnCompleteOnStart(bool isOn) + { + this.onCompleteOnStart = isOn; + return this; + } + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 + public LTDescr setRect(RectTransform rect) + { + this.rectTransform = rect; + return this; + } + + public LTDescr setSprites(UnityEngine.Sprite[] sprites) + { + this.sprites = sprites; + return this; + } + + public LTDescr setFrameRate(float frameRate) + { + this.time = this.sprites.Length / frameRate; + return this; + } +#endif + + /** + * Have a method called when the tween starts + * @method setOnStart + * @param {Action<>} onStart:Action<> the method that should be called when the tween is starting ex: tweenStarted( ){ } + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * C#:
+ * LeanTween.moveX(gameObject, 5f, 2.0f ).setOnStart( ()=>{ Debug.Log("I started!"); }); + * Javascript:
+ * LeanTween.moveX(gameObject, 5f, 2.0f ).setOnStart( function(){ Debug.Log("I started!"); } ); + */ + public LTDescr setOnStart(Action onStart) + { + this._optional.onStart = onStart; + return this; + } + + /** + * Set the direction of a tween -1f for backwards 1f for forwards (currently only bezier and spline paths are supported) + * @method setDirection + * @param {float} direction:float the direction that the tween should run, -1f for backwards 1f for forwards + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.moveSpline(gameObject, new Vector3[]{new Vector3(0f,0f,0f),new Vector3(1f,0f,0f),new Vector3(1f,0f,0f),new Vector3(1f,0f,1f)}, 1.5f).setDirection(-1f);
+ */ + + public LTDescr setDirection(float direction) + { + if (this.direction != -1f && this.direction != 1f) + { + Debug.LogWarning("You have passed an incorrect direction of '" + direction + "', direction must be -1f or 1f"); + return this; + } + + if (this.direction != direction) + { + // Debug.Log("reverse path:"+this.path+" spline:"+this._optional.spline+" hasInitiliazed:"+this.hasInitiliazed); + if (this.hasInitiliazed) + { + this.direction = direction; + } + else + { + if (this._optional.path != null) + { + this._optional.path = new LTBezierPath(LTUtility.reverse(this._optional.path.pts)); + } + else if (this._optional.spline != null) + { + this._optional.spline = new LTSpline(LTUtility.reverse(this._optional.spline.pts)); + } + // this.passed = this.time - this.passed; + } + } + + return this; + } + + /** + * Set whether or not the tween will recursively effect an objects children in the hierarchy + * @method setRecursive + * @param {bool} useRecursion:bool whether the tween will recursively effect an objects children in the hierarchy + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.alpha(gameObject, 0f, 1f).setRecursive(true);
+ */ + + public LTDescr setRecursive(bool useRecursion) + { + this.useRecursion = useRecursion; + + return this; + } +} + +//} diff --git a/KFAttached/LeanTween/Framework/LTDescr.cs.meta b/KFAttached/LeanTween/Framework/LTDescr.cs.meta new file mode 100644 index 0000000..141b45c --- /dev/null +++ b/KFAttached/LeanTween/Framework/LTDescr.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 381c8d6fb1acdc348870a7147bc98723 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/LeanTween/Framework/LTDescrOptional.cs b/KFAttached/LeanTween/Framework/LTDescrOptional.cs new file mode 100644 index 0000000..b751b0b --- /dev/null +++ b/KFAttached/LeanTween/Framework/LTDescrOptional.cs @@ -0,0 +1,99 @@ +//namespace DentedPixel{ +using System; +using UnityEngine; + +public class LTDescrOptional +{ + + public Transform toTrans { get; set; } + public Vector3 point { get; set; } + public Vector3 axis { get; set; } + public float lastVal { get; set; } + public Quaternion origRotation { get; set; } + public LTBezierPath path { get; set; } + public LTSpline spline { get; set; } + public AnimationCurve animationCurve; + public int initFrameCount; + public Color color; + + public LTRect ltRect { get; set; } // maybe get rid of this eventually + + public Action onUpdateFloat { get; set; } + public Action onUpdateFloatRatio { get; set; } + public Action onUpdateFloatObject { get; set; } + public Action onUpdateVector2 { get; set; } + public Action onUpdateVector3 { get; set; } + public Action onUpdateVector3Object { get; set; } + public Action onUpdateColor { get; set; } + public Action onUpdateColorObject { get; set; } + public Action onComplete { get; set; } + public Action onCompleteObject { get; set; } + public object onCompleteParam { get; set; } + public object onUpdateParam { get; set; } + public Action onStart { get; set; } + + + // #if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 + // public SpriteRenderer spriteRen { get; set; } + // #endif + // + // #if LEANTWEEN_1 + // public Hashtable optional; + // #endif + // #if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 + // public RectTransform rectTransform; + // public UnityEngine.UI.Text uiText; + // public UnityEngine.UI.Image uiImage; + // public UnityEngine.Sprite[] sprites; + // #endif + + + public void reset() + { + animationCurve = null; + + this.onUpdateFloat = null; + this.onUpdateFloatRatio = null; + this.onUpdateVector2 = null; + this.onUpdateVector3 = null; + this.onUpdateFloatObject = null; + this.onUpdateVector3Object = null; + this.onUpdateColor = null; + this.onComplete = null; + this.onCompleteObject = null; + this.onCompleteParam = null; + this.onStart = null; + + this.point = Vector3.zero; + this.initFrameCount = 0; + } + + public void callOnUpdate(float val, float ratioPassed) + { + if (this.onUpdateFloat != null) + this.onUpdateFloat(val); + + if (this.onUpdateFloatRatio != null) + { + this.onUpdateFloatRatio(val, ratioPassed); + } + else if (this.onUpdateFloatObject != null) + { + this.onUpdateFloatObject(val, this.onUpdateParam); + } + else if (this.onUpdateVector3Object != null) + { + this.onUpdateVector3Object(LTDescr.newVect, this.onUpdateParam); + } + else if (this.onUpdateVector3 != null) + { + this.onUpdateVector3(LTDescr.newVect); + } + else if (this.onUpdateVector2 != null) + { + this.onUpdateVector2(new Vector2(LTDescr.newVect.x, LTDescr.newVect.y)); + } + } +} + +//} diff --git a/KFAttached/LeanTween/Framework/LTDescrOptional.cs.meta b/KFAttached/LeanTween/Framework/LTDescrOptional.cs.meta new file mode 100644 index 0000000..615e564 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LTDescrOptional.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c1ba8f1ef97134cb39b52ae26678db63 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/LeanTween/Framework/LTSeq.cs b/KFAttached/LeanTween/Framework/LTSeq.cs new file mode 100644 index 0000000..c7b1955 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LTSeq.cs @@ -0,0 +1,243 @@ +using UnityEngine; + +/** +* Internal Representation of a Sequence
+*
+*   

Example:

+* var seq = LeanTween.sequence();
+* seq.append(1f); // delay everything one second
+* seq.append( () => { // fire an event before start
+*  Debug.Log("I have started");
+* });
+* seq.append( LeanTween.move(cube1, Vector3.one * 10f, 1f) ); // do a tween
+* seq.append( (object obj) => { // fire event after tween
+*  var dict = obj as Dictionary;
+*  Debug.Log("We are done now obj value:"+dict["hi"]);
+* }, new Dictionary(){ {"hi","sup"} } );
+* @class LTSeq +* @constructor +*/ +public class LTSeq +{ + + public LTSeq previous; + + public LTSeq current; + + public LTDescr tween; + + public float totalDelay; + + public float timeScale; + + private int debugIter; + + public uint counter; + + public bool toggle = false; + + private uint _id; + + public int id + { + get + { + uint toId = _id | counter << 16; + + /*uint backId = toId & 0xFFFF; + uint backCounter = toId >> 16; + if(_id!=backId || backCounter!=counter){ + Debug.LogError("BAD CONVERSION toId:"+_id); + }*/ + + return (int)toId; + } + } + + public void reset() + { + previous = null; + tween = null; + totalDelay = 0f; + } + + public void init(uint id, uint global_counter) + { + reset(); + _id = id; + + counter = global_counter; + + this.current = this; + } + + private LTSeq addOn() + { + this.current.toggle = true; + LTSeq lastCurrent = this.current; + this.current = LeanTween.sequence(true); + // Debug.Log("this.current:" + this.current.id + " lastCurrent:" + lastCurrent.id); + this.current.previous = lastCurrent; + lastCurrent.toggle = false; + this.current.totalDelay = lastCurrent.totalDelay; + this.current.debugIter = lastCurrent.debugIter + 1; + return current; + } + + private float addPreviousDelays() + { + // Debug.Log("delay:"+delay+" count:"+this.current.count+" this.current.totalDelay:"+this.current.totalDelay); + + LTSeq prev = this.current.previous; + + if (prev != null && prev.tween != null) + { + return this.current.totalDelay + prev.tween.time; + } + return this.current.totalDelay; + } + + /** + * Add a time delay to the sequence + * @method append (delay) + * @param {float} delay:float amount of time to add to the sequence + * @return {LTSeq} LTDescr an object that distinguishes the tween + * var seq = LeanTween.sequence();
+ * seq.append(1f); // delay everything one second
+ * seq.append( LeanTween.move(cube1, Vector3.one * 10f, 1f) ); // do a tween
+ */ + public LTSeq append(float delay) + { + this.current.totalDelay += delay; + + return this.current; + } + + /** + * Add a time delay to the sequence + * @method append (method) + * @param {System.Action} callback:System.Action method you want to be called + * @return {LTSeq} LTSeq an object that you can add tweens, methods and time on to + * @example + * var seq = LeanTween.sequence();
+ * seq.append( () => { // fire an event before start
+ *  Debug.Log("I have started");
+ * });
+ * seq.append( LeanTween.move(cube1, Vector3.one * 10f, 1f) ); // do a tween
+ * seq.append( () => { // fire event after tween
+ *  Debug.Log("We are done now");
+ * });;
+ */ + public LTSeq append(System.Action callback) + { + LTDescr newTween = LeanTween.delayedCall(0f, callback); + // Debug.Log("newTween:" + newTween); + return append(newTween); + } + + /** + * Add a time delay to the sequence + * @method add (method(object)) + * @param {System.Action} callback:System.Action method you want to be called + * @return {LTSeq} LTSeq an object that you can add tweens, methods and time on to + * @example + * var seq = LeanTween.sequence();
+ * seq.append( () => { // fire an event before start
+ *  Debug.Log("I have started");
+ * });
+ * seq.append( LeanTween.move(cube1, Vector3.one * 10f, 1f) ); // do a tween
+ * seq.append((object obj) => { // fire event after tween + *  var dict = obj as Dictionary; + *  Debug.Log("We are done now obj value:"+dict["hi"]); + *  }, new Dictionary(){ {"hi","sup"} } ); + */ + public LTSeq append(System.Action callback, object obj) + { + append(LeanTween.delayedCall(0f, callback).setOnCompleteParam(obj)); + + return addOn(); + } + + public LTSeq append(GameObject gameObject, System.Action callback) + { + append(LeanTween.delayedCall(gameObject, 0f, callback)); + + return addOn(); + } + + public LTSeq append(GameObject gameObject, System.Action callback, object obj) + { + append(LeanTween.delayedCall(gameObject, 0f, callback).setOnCompleteParam(obj)); + + return addOn(); + } + + /** + * Retrieve a sequencer object where you can easily chain together tweens and methods one after another + * + * @method add (tween) + * @return {LTSeq} LTSeq an object that you can add tweens, methods and time on to + * @example + * var seq = LeanTween.sequence();
+ * seq.append( LeanTween.move(cube1, Vector3.one * 10f, 1f) ); // do a move tween
+ * seq.append( LeanTween.rotateAround( avatar1, Vector3.forward, 360f, 1f ) ); // then do a rotate tween
+ */ + public LTSeq append(LTDescr tween) + { + this.current.tween = tween; + + // Debug.Log("tween:" + tween + " delay:" + this.current.totalDelay); + + this.current.totalDelay = addPreviousDelays(); + + tween.setDelay(this.current.totalDelay); + + return addOn(); + } + + public LTSeq insert(LTDescr tween) + { + this.current.tween = tween; + + tween.setDelay(addPreviousDelays()); + + return addOn(); + } + + + public LTSeq setScale(float timeScale) + { + // Debug.Log("this.current:" + this.current.previous.debugIter+" tween:"+this.current.previous.tween); + setScaleRecursive(this.current, timeScale, 500); + + return addOn(); + } + + private void setScaleRecursive(LTSeq seq, float timeScale, int count) + { + if (count > 0) + { + this.timeScale = timeScale; + + // Debug.Log("seq.count:" + count + " seq.tween:" + seq.tween); + seq.totalDelay *= timeScale; + if (seq.tween != null) + { + // Debug.Log("seq.tween.time * timeScale:" + seq.tween.time * timeScale + " seq.totalDelay:"+seq.totalDelay +" time:"+seq.tween.time+" seq.tween.delay:"+seq.tween.delay); + if (seq.tween.time != 0f) + seq.tween.setTime(seq.tween.time * timeScale); + seq.tween.setDelay(seq.tween.delay * timeScale); + } + + if (seq.previous != null) + setScaleRecursive(seq.previous, timeScale, count - 1); + } + } + + public LTSeq reverse() + { + + return addOn(); + } + +} diff --git a/KFAttached/LeanTween/Framework/LTSeq.cs.meta b/KFAttached/LeanTween/Framework/LTSeq.cs.meta new file mode 100644 index 0000000..cb77fb8 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LTSeq.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c88dbe4cdd9944f198e9796ee394c86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/LeanTween/Framework/LeanAudio.cs b/KFAttached/LeanTween/Framework/LeanAudio.cs new file mode 100644 index 0000000..5c135c9 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LeanAudio.cs @@ -0,0 +1,471 @@ + +using UnityEngine; + +public class LeanAudioStream +{ + + public int position = 0; + + public AudioClip audioClip; + public float[] audioArr; + + public LeanAudioStream(float[] audioArr) + { + this.audioArr = audioArr; + } + + public void OnAudioRead(float[] data) + { + int count = 0; + while (count < data.Length) + { + data[count] = audioArr[this.position]; + position++; + count++; + } + } + + public void OnAudioSetPosition(int newPosition) + { + this.position = newPosition; + } +} + +/** +* Create Audio dynamically and easily playback +* +* @class LeanAudio +* @constructor +*/ +public class LeanAudio : object +{ + + public static float MIN_FREQEUNCY_PERIOD = 0.000115f; + public static int PROCESSING_ITERATIONS_MAX = 50000; + public static float[] generatedWaveDistances; + public static int generatedWaveDistancesCount = 0; + + private static float[] longList; + + public static LeanAudioOptions options() + { + if (generatedWaveDistances == null) + { + generatedWaveDistances = new float[PROCESSING_ITERATIONS_MAX]; + longList = new float[PROCESSING_ITERATIONS_MAX]; + } + return new LeanAudioOptions(); + } + + public static LeanAudioStream createAudioStream(AnimationCurve volume, AnimationCurve frequency, LeanAudioOptions options = null) + { + if (options == null) + options = new LeanAudioOptions(); + + options.useSetData = false; + + int generatedWavePtsLength = createAudioWave(volume, frequency, options); + createAudioFromWave(generatedWavePtsLength, options); + + return options.stream; + } + + /** + * Create dynamic audio from a set of Animation Curves and other options. + * + * @method createAudio + * @param {AnimationCurve} volumeCurve:AnimationCurve describing the shape of the audios volume (from 0-1). The length of the audio is dicated by the end value here. + * @param {AnimationCurve} frequencyCurve:AnimationCurve describing the width of the oscillations between the sound waves in seconds. Large numbers mean a lower note, while higher numbers mean a tighter frequency and therefor a higher note. Values are usually between 0.01 and 0.000001 (or smaller) + * @param {LeanAudioOptions} options:LeanAudioOptions You can pass any other values in here like vibrato or the frequency you would like the sound to be encoded at. See LeanAudioOptions for more details. + * @return {AudioClip} AudioClip of the procedurally generated audio + * @example + * AnimationCurve volumeCurve = new AnimationCurve( new Keyframe(0f, 1f, 0f, -1f), new Keyframe(1f, 0f, -1f, 0f));
+ * AnimationCurve frequencyCurve = new AnimationCurve( new Keyframe(0f, 0.003f, 0f, 0f), new Keyframe(1f, 0.003f, 0f, 0f));
+ * AudioClip audioClip = LeanAudio.createAudio(volumeCurve, frequencyCurve, LeanAudio.options().setVibrato( new Vector3[]{ new Vector3(0.32f,0f,0f)} ));
+ */ + public static AudioClip createAudio(AnimationCurve volume, AnimationCurve frequency, LeanAudioOptions options = null) + { + if (options == null) + options = new LeanAudioOptions(); + + int generatedWavePtsLength = createAudioWave(volume, frequency, options); + // Debug.Log("generatedWavePtsLength:"+generatedWavePtsLength); + return createAudioFromWave(generatedWavePtsLength, options); + } + + private static int createAudioWave(AnimationCurve volume, AnimationCurve frequency, LeanAudioOptions options) + { + float time = volume[volume.length - 1].time; + int listLength = 0; + // List list = new List(); + + // generatedWaveDistances = new List(); + // float[] vibratoValues = new float[ vibrato.Length ]; + float passed = 0f; + for (int i = 0; i < PROCESSING_ITERATIONS_MAX; i++) + { + float f = frequency.Evaluate(passed); + if (f < MIN_FREQEUNCY_PERIOD) + f = MIN_FREQEUNCY_PERIOD; + float height = volume.Evaluate(passed + 0.5f * f); + if (options.vibrato != null) + { + for (int j = 0; j < options.vibrato.Length; j++) + { + float peakMulti = Mathf.Abs(Mathf.Sin(1.5708f + passed * (1f / options.vibrato[j][0]) * Mathf.PI)); + float diff = (1f - options.vibrato[j][1]); + peakMulti = options.vibrato[j][1] + diff * peakMulti; + height *= peakMulti; + } + } + + + // Debug.Log("i:"+i+" f:"+f+" passed:"+passed+" height:"+height+" time:"+time); + if (passed + 0.5f * f >= time) + break; + if (listLength >= PROCESSING_ITERATIONS_MAX - 1) + { + Debug.LogError("LeanAudio has reached it's processing cap. To avoid this error increase the number of iterations ex: LeanAudio.PROCESSING_ITERATIONS_MAX = " + (PROCESSING_ITERATIONS_MAX * 2)); + break; + } + else + { + int distPoint = listLength / 2; + + //generatedWaveDistances.Add( f ); + passed += f; + + generatedWaveDistances[distPoint] = passed; + //Debug.Log("distPoint:"+distPoint+" passed:"+passed); + + //list.Add( passed ); + //list.Add( i%2==0 ? -height : height ); + + longList[listLength] = passed; + longList[listLength + 1] = i % 2 == 0 ? -height : height; + } + + + + listLength += 2; + + } + + listLength += -2; + generatedWaveDistancesCount = listLength / 2; + + /*float[] wave = new float[ listLength ]; + for(int i = 0; i < wave.Length; i++){ + wave[i] = longList[i]; + }*/ + return listLength; + } + + private static AudioClip createAudioFromWave(int waveLength, LeanAudioOptions options) + { + float time = longList[waveLength - 2]; + float[] audioArr = new float[(int)(options.frequencyRate * time)]; + + int waveIter = 0; + float subWaveDiff = longList[waveIter]; + float subWaveTimeLast = 0f; + float subWaveTime = longList[waveIter]; + float waveHeight = longList[waveIter + 1]; + for (int i = 0; i < audioArr.Length; i++) + { + float passedTime = (float)i / (float)options.frequencyRate; + if (passedTime > longList[waveIter]) + { + subWaveTimeLast = longList[waveIter]; + waveIter += 2; + subWaveDiff = longList[waveIter] - longList[waveIter - 2]; + waveHeight = longList[waveIter + 1]; + // Debug.Log("passed wave i:"+i); + } + subWaveTime = passedTime - subWaveTimeLast; + float ratioElapsed = subWaveTime / subWaveDiff; + + float value = Mathf.Sin(ratioElapsed * Mathf.PI); + + if (options.waveStyle == LeanAudioOptions.LeanAudioWaveStyle.Square) + { + if (value > 0f) + value = 1f; + if (value < 0f) + value = -1f; + } + else if (options.waveStyle == LeanAudioOptions.LeanAudioWaveStyle.Sawtooth) + { + float sign = value > 0f ? 1f : -1f; + if (ratioElapsed < 0.5f) + { + value = (ratioElapsed * 2f) * sign; + } + else + { // 0.5f - 1f + value = (1f - ratioElapsed) * 2f * sign; + } + } + else if (options.waveStyle == LeanAudioOptions.LeanAudioWaveStyle.Noise) + { + float peakMulti = (1f - options.waveNoiseInfluence) + Mathf.PerlinNoise(0f, passedTime * options.waveNoiseScale) * options.waveNoiseInfluence; + + /*if(i<25){ + Debug.Log("passedTime:"+passedTime+" peakMulti:"+peakMulti+" infl:"+options.waveNoiseInfluence); + }*/ + + value *= peakMulti; + } + + //if(i<25) + // Debug.Log("passedTime:"+passedTime+" value:"+value+" ratioElapsed:"+ratioElapsed+" subWaveTime:"+subWaveTime+" subWaveDiff:"+subWaveDiff); + + value *= waveHeight; + + + if (options.modulation != null) + { + for (int k = 0; k < options.modulation.Length; k++) + { + float peakMulti = Mathf.Abs(Mathf.Sin(1.5708f + passedTime * (1f / options.modulation[k][0]) * Mathf.PI)); + float diff = (1f - options.modulation[k][1]); + peakMulti = options.modulation[k][1] + diff * peakMulti; + // if(k<10){ + // Debug.Log("k:"+k+" peakMulti:"+peakMulti+" value:"+value+" after:"+(value*peakMulti)); + // } + value *= peakMulti; + } + } + + audioArr[i] = value; + // Debug.Log("pt:"+pt+" i:"+i+" val:"+audioArr[i]+" len:"+audioArr.Length); + } + + + int lengthSamples = audioArr.Length; + +#if UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 + bool is3dSound = false; + AudioClip audioClip = AudioClip.Create("Generated Audio", lengthSamples, 1, options.frequencyRate, is3dSound, false); +#else + AudioClip audioClip = null; + if (options.useSetData) + { + audioClip = AudioClip.Create("Generated Audio", lengthSamples, 1, options.frequencyRate, false, null, OnAudioSetPosition); + audioClip.SetData(audioArr, 0); + } + else + { + options.stream = new LeanAudioStream(audioArr); + // Debug.Log("len:"+audioArr.Length+" lengthSamples:"+lengthSamples+" freqRate:"+options.frequencyRate); + audioClip = AudioClip.Create("Generated Audio", lengthSamples, 1, options.frequencyRate, false, options.stream.OnAudioRead, options.stream.OnAudioSetPosition); + options.stream.audioClip = audioClip; + } + +#endif + + return audioClip; + } + + private static void OnAudioSetPosition(int newPosition) + { + + } + + public static AudioClip generateAudioFromCurve(AnimationCurve curve, int frequencyRate = 44100) + { + float curveTime = curve[curve.length - 1].time; + float time = curveTime; + float[] audioArr = new float[(int)(frequencyRate * time)]; + + // Debug.Log("curveTime:"+curveTime+" AudioSettings.outputSampleRate:"+AudioSettings.outputSampleRate); + for (int i = 0; i < audioArr.Length; i++) + { + float pt = (float)i / (float)frequencyRate; + audioArr[i] = curve.Evaluate(pt); + // Debug.Log("pt:"+pt+" i:"+i+" val:"+audioArr[i]+" len:"+audioArr.Length); + } + + int lengthSamples = audioArr.Length;//(int)( (float)frequencyRate * curveTime ); +#if UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 + bool is3dSound = false; + AudioClip audioClip = AudioClip.Create("Generated Audio", lengthSamples, 1, frequencyRate, is3dSound, false); +#else + AudioClip audioClip = AudioClip.Create("Generated Audio", lengthSamples, 1, frequencyRate, false); +#endif + audioClip.SetData(audioArr, 0); + + return audioClip; + } + + public static AudioSource play(AudioClip audio, float volume) + { + AudioSource audioSource = playClipAt(audio, Vector3.zero); + audioSource.volume = volume; + return audioSource; + } + + public static AudioSource play(AudioClip audio) + { + return playClipAt(audio, Vector3.zero); + } + + public static AudioSource play(AudioClip audio, Vector3 pos) + { + return playClipAt(audio, pos); + } + + public static AudioSource play(AudioClip audio, Vector3 pos, float volume) + { + // Debug.Log("audio length:"+audio.length); + AudioSource audioSource = playClipAt(audio, pos); + audioSource.minDistance = 1f; + //audioSource.pitch = pitch; + audioSource.volume = volume; + + return audioSource; + } + + public static AudioSource playClipAt(AudioClip clip, Vector3 pos) + { + GameObject tempGO = new GameObject(); // create the temp object + tempGO.transform.position = pos; // set its position + AudioSource aSource = tempGO.AddComponent(); // add an audio source + aSource.clip = clip; // define the clip + aSource.Play(); // start the sound + GameObject.Destroy(tempGO, clip.length); // destroy object after clip duration + return aSource; // return the AudioSource reference + } + + public static void printOutAudioClip(AudioClip audioClip, ref AnimationCurve curve, float scaleX = 1f) + { + // Debug.Log("Audio channels:"+audioClip.channels+" frequency:"+audioClip.frequency+" length:"+audioClip.length+" samples:"+audioClip.samples); + float[] samples = new float[audioClip.samples * audioClip.channels]; + audioClip.GetData(samples, 0); + int i = 0; + + Keyframe[] frames = new Keyframe[samples.Length]; + while (i < samples.Length) + { + frames[i] = new Keyframe((float)i * scaleX, samples[i]); + ++i; + } + curve = new AnimationCurve(frames); + } +} + + +/** +* Pass in options to LeanAudio +* +* @class LeanAudioOptions +* @constructor +*/ +public class LeanAudioOptions : object +{ + + public enum LeanAudioWaveStyle + { + Sine, + Square, + Sawtooth, + Noise + } + + public LeanAudioWaveStyle waveStyle = LeanAudioWaveStyle.Sine; + public Vector3[] vibrato; + public Vector3[] modulation; + public int frequencyRate = 44100; + public float waveNoiseScale = 1000; + public float waveNoiseInfluence = 1f; + + public bool useSetData = true; + public LeanAudioStream stream; + + public LeanAudioOptions() { } + + /** + * Set the frequency for the audio is encoded. 44100 is CD quality, but you can usually get away with much lower (or use a lower amount to get a more 8-bit sound). + * + * @method setFrequency + * @param {int} frequencyRate:int of the frequency you wish to encode the AudioClip at + * @return {LeanAudioOptions} LeanAudioOptions describing optional values + * @example + * AnimationCurve volumeCurve = new AnimationCurve( new Keyframe(0f, 1f, 0f, -1f), new Keyframe(1f, 0f, -1f, 0f));
+ * AnimationCurve frequencyCurve = new AnimationCurve( new Keyframe(0f, 0.003f, 0f, 0f), new Keyframe(1f, 0.003f, 0f, 0f));
+ * AudioClip audioClip = LeanAudio.createAudio(volumeCurve, frequencyCurve, LeanAudio.options().setVibrato( new Vector3[]{ new Vector3(0.32f,0f,0f)} ).setFrequency(12100) );
+ */ + public LeanAudioOptions setFrequency(int frequencyRate) + { + this.frequencyRate = frequencyRate; + return this; + } + + /** + * Set details about the shape of the curve by adding vibrato modulations through it (alters the peak values giving it a wah-wah effect). You can add as many as you want to sculpt out more detail in the sound wave. + * + * @method setVibrato + * @param {Vector3[]} vibratoArray:Vector3[] The first value is the period in seconds that you wish to have the vibrato wave fluctuate at. The second value is the minimum height you wish the vibrato wave to dip down to (default is zero). The third is reserved for future effects. + * @return {LeanAudioOptions} LeanAudioOptions describing optional values + * @example + * AnimationCurve volumeCurve = new AnimationCurve( new Keyframe(0f, 1f, 0f, -1f), new Keyframe(1f, 0f, -1f, 0f));
+ * AnimationCurve frequencyCurve = new AnimationCurve( new Keyframe(0f, 0.003f, 0f, 0f), new Keyframe(1f, 0.003f, 0f, 0f));
+ * AudioClip audioClip = LeanAudio.createAudio(volumeCurve, frequencyCurve, LeanAudio.options().setVibrato( new Vector3[]{ new Vector3(0.32f,0.3f,0f)} ).setFrequency(12100) );
+ */ + public LeanAudioOptions setVibrato(Vector3[] vibrato) + { + this.vibrato = vibrato; + return this; + } + + /* + public LeanAudioOptions setModulation( Vector3[] modulation ){ + this.modulation = modulation; + return this; + }*/ + + public LeanAudioOptions setWaveSine() + { + this.waveStyle = LeanAudioWaveStyle.Sine; + return this; + } + + public LeanAudioOptions setWaveSquare() + { + this.waveStyle = LeanAudioWaveStyle.Square; + return this; + } + + public LeanAudioOptions setWaveSawtooth() + { + this.waveStyle = LeanAudioWaveStyle.Sawtooth; + return this; + } + + public LeanAudioOptions setWaveNoise() + { + this.waveStyle = LeanAudioWaveStyle.Noise; + return this; + } + + public LeanAudioOptions setWaveStyle(LeanAudioWaveStyle style) + { + this.waveStyle = style; + return this; + } + + + public LeanAudioOptions setWaveNoiseScale(float waveScale) + { + this.waveNoiseScale = waveScale; + return this; + } + + public LeanAudioOptions setWaveNoiseInfluence(float influence) + { + this.waveNoiseInfluence = influence; + return this; + } +} + + diff --git a/KFAttached/LeanTween/Framework/LeanAudio.cs.meta b/KFAttached/LeanTween/Framework/LeanAudio.cs.meta new file mode 100644 index 0000000..272a1f7 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LeanAudio.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52e41e970d9353942b27458440bec9eb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/LeanTween/Framework/LeanSmooth.cs b/KFAttached/LeanTween/Framework/LeanSmooth.cs new file mode 100644 index 0000000..fa948fb --- /dev/null +++ b/KFAttached/LeanTween/Framework/LeanSmooth.cs @@ -0,0 +1,363 @@ +using UnityEngine; + +/** +* Use these smooth methods to move one value towards another

+* Example:
fromY = LeanSmooth.spring(fromY, followArrow.localPosition.y, ref velocityY, 1.1f);
+* fromVec3 = LeanSmooth.damp(fromVec3, dude5Title.localPosition, ref velocityVec3, 1.1f);
+* fromColor = LeanSmooth.damp(fromColor, dude5Title.GetComponent().material.color, ref velocityColor, 1.1f);
+* Debug.Log("Smoothed y:" + fromY + " vec3:" + fromVec3 + " color:" + fromColor);
+* +* @class LeanSmooth +*/ + +public class LeanSmooth +{ + + + /** + * Moves one value towards another (eases in and out to destination with no overshoot) + * + * @method LeanSmooth.damp (float) + * @param {float} current:float the current value + * @param {float} target:float the value we are trying to reach + * @param {float} currentVelocity:float the current velocity of the value + * @param {float} smoothTime:float roughly the time it takes to reach the destination + * @param {float} maxSpeed:float the top speed you want the value to move at (defaults to unlimited -1f) + * @param {float} deltaTime:float the difference in time since the method was called (defaults to Time.deltaTime) + * @example + * followVar = LeanSmooth.damp(followVar, destinationVar, ref followVelocity, 1.1f);\n + * Debug.Log("current:"+followVar); + */ + public static float damp(float current, float target, ref float currentVelocity, float smoothTime, float maxSpeed = -1f, float deltaTime = -1f) + { + if (deltaTime < 0f) + deltaTime = Time.deltaTime; + + smoothTime = Mathf.Max(0.0001f, smoothTime); + float num = 2f / smoothTime; + float num2 = num * deltaTime; + float num3 = 1f / (1f + num2 + 0.48f * num2 * num2 + 0.235f * num2 * num2 * num2); + float num4 = current - target; + float num5 = target; + if (maxSpeed > 0f) + { + float num6 = maxSpeed * smoothTime; + num4 = Mathf.Clamp(num4, -num6, num6); + } + target = current - num4; + float num7 = (currentVelocity + num * num4) * deltaTime; + currentVelocity = (currentVelocity - num * num7) * num3; + float num8 = target + (num4 + num7) * num3; + if (num5 - current > 0f == num8 > num5) + { + num8 = num5; + currentVelocity = (num8 - num5) / deltaTime; + } + return num8; + } + + /** + * Moves one value towards another (eases in and out to destination with no overshoot) + * + * @method LeanSmooth.damp (Vector3) + * @param {float} current:Vector3 the current value + * @param {float} target:Vector3 the value we are trying to reach + * @param {float} currentVelocity:Vector3 the current velocity of the value + * @param {float} smoothTime:float roughly the time it takes to reach the destination + * @param {float} maxSpeed:float the top speed you want the value to move at (defaults to unlimited -1f) + * @param {float} deltaTime:float the difference in time since the method was called (defaults to Time.deltaTime) + * @example + * transform.position = LeanSmooth.damp(transform.position, destTrans.position, ref followVelocity, 1.1f);\n + * Debug.Log("current:"+transform.position); + */ + public static Vector3 damp(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime, float maxSpeed = -1f, float deltaTime = -1f) + { + float x = damp(current.x, target.x, ref currentVelocity.x, smoothTime, maxSpeed, deltaTime); + float y = damp(current.y, target.y, ref currentVelocity.y, smoothTime, maxSpeed, deltaTime); + float z = damp(current.z, target.z, ref currentVelocity.z, smoothTime, maxSpeed, deltaTime); + + return new Vector3(x, y, z); + } + + /** + * Moves one color value towards another color (eases in and out to destination with no overshoot) + * + * @method LeanSmooth.damp (Color) + * @param {float} current:Color the current value + * @param {float} target:Color the value we are trying to reach + * @param {float} currentVelocity:Color the current velocity of the value + * @param {float} smoothTime:float roughly the time it takes to reach the destination + * @param {float} maxSpeed:float the top speed you want the value to move at (defaults to unlimited -1f) + * @param {float} deltaTime:float the difference in time since the method was called (defaults to Time.deltaTime) + * @example + * fromColor = LeanSmooth.damp(fromColor, transform.GetComponent().material.color, ref velocityColor, 1.1f);\n + * Debug.Log("current:"+fromColor); + */ + public static Color damp(Color current, Color target, ref Color currentVelocity, float smoothTime, float maxSpeed = -1f, float deltaTime = -1f) + { + float r = damp(current.r, target.r, ref currentVelocity.r, smoothTime, maxSpeed, deltaTime); + float g = damp(current.g, target.g, ref currentVelocity.g, smoothTime, maxSpeed, deltaTime); + float b = damp(current.b, target.b, ref currentVelocity.b, smoothTime, maxSpeed, deltaTime); + float a = damp(current.a, target.a, ref currentVelocity.a, smoothTime, maxSpeed, deltaTime); + + return new Color(r, g, b, a); + } + + /** + * Moves one value towards another (eases in and out to destination with possible overshoot bounciness) + * + * @method LeanSmooth.spring (float) + * @param {float} current:float the current value + * @param {float} target:float the value we are trying to reach + * @param {float} currentVelocity:float the current velocity of the value + * @param {float} smoothTime:float roughly the time it takes to reach the destination + * @param {float} maxSpeed:float the top speed you want the value to move at (defaults to unlimited -1f) + * @param {float} deltaTime:float the difference in time since the method was called (defaults to Time.deltaTime) + * @param {float} [friction]:float rate at which the spring is slowed down once it reaches it's destination + * @param {float} [accelRate]:float the rate it accelerates from it's initial position + * @example + * followVar = LeanSmooth.spring(followVar, destinationVar, ref followVelocity, 1.1f);\n + * Debug.Log("current:"+followVar); + */ + public static float spring(float current, float target, ref float currentVelocity, float smoothTime, float maxSpeed = -1f, float deltaTime = -1f, float friction = 2f, float accelRate = 0.5f) + { + if (deltaTime < 0f) + deltaTime = Time.deltaTime; + + float diff = target - current; + + currentVelocity += deltaTime / smoothTime * accelRate * diff; + + currentVelocity *= (1f - deltaTime * friction); + + if (maxSpeed > 0f && maxSpeed < Mathf.Abs(currentVelocity)) + currentVelocity = maxSpeed * Mathf.Sign(currentVelocity); + + float returned = current + currentVelocity; + + return returned; + } + + /** + * Moves one value towards another (eases in and out to destination with possible overshoot bounciness) + * + * @method LeanSmooth.spring (Vector3) + * @param {Vector3} current:float the current value + * @param {Vector3} target:float the value we are trying to reach + * @param {Vector3} currentVelocity:float the current velocity of the value + * @param {float} smoothTime:float roughly the time it takes to reach the destination + * @param {float} maxSpeed:float the top speed you want the value to move at (defaults to unlimited -1f) + * @param {float} deltaTime:float the difference in time since the method was called (defaults to Time.deltaTime) + * @param {float} [friction]:float rate at which the spring is slowed down once it reaches it's destination + * @param {float} [accelRate]:float the rate it accelerates from it's initial position + * @example + * transform.position = LeanSmooth.spring(transform.position, destTrans.position, ref followVelocity, 1.1f);\n + * Debug.Log("current:"+transform.position); + */ + public static Vector3 spring(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime, float maxSpeed = -1f, float deltaTime = -1f, float friction = 2f, float accelRate = 0.5f) + { + float x = spring(current.x, target.x, ref currentVelocity.x, smoothTime, maxSpeed, deltaTime, friction, accelRate); + float y = spring(current.y, target.y, ref currentVelocity.y, smoothTime, maxSpeed, deltaTime, friction, accelRate); + float z = spring(current.z, target.z, ref currentVelocity.z, smoothTime, maxSpeed, deltaTime, friction, accelRate); + + return new Vector3(x, y, z); + } + + /** + * Moves one color towards another (eases in and out to destination with possible overshoot bounciness) + * + * @method LeanSmooth.spring (Color) + * @param {Color} current:float the current value + * @param {Color} target:float the value we are trying to reach + * @param {Color} currentVelocity:float the current velocity of the value + * @param {float} smoothTime:float roughly the time it takes to reach the destination + * @param {float} maxSpeed:float the top speed you want the value to move at (defaults to unlimited -1f) + * @param {float} deltaTime:float the difference in time since the method was called (defaults to Time.deltaTime) + * @param {float} [friction]:float rate at which the spring is slowed down once it reaches it's destination + * @param {float} [accelRate]:float the rate it accelerates from it's initial position + * @example + * fromColor = LeanSmooth.spring(fromColor, transform.GetComponent().material.color, ref velocityColor, 1.1f);\n + * Debug.Log("current:"+fromColor); + */ + public static Color spring(Color current, Color target, ref Color currentVelocity, float smoothTime, float maxSpeed = -1f, float deltaTime = -1f, float friction = 2f, float accelRate = 0.5f) + { + float r = spring(current.r, target.r, ref currentVelocity.r, smoothTime, maxSpeed, deltaTime, friction, accelRate); + float g = spring(current.g, target.g, ref currentVelocity.g, smoothTime, maxSpeed, deltaTime, friction, accelRate); + float b = spring(current.b, target.b, ref currentVelocity.b, smoothTime, maxSpeed, deltaTime, friction, accelRate); + float a = spring(current.a, target.a, ref currentVelocity.a, smoothTime, maxSpeed, deltaTime, friction, accelRate); + + return new Color(r, g, b, a); + } + + /** + * Moves one value towards another (at a constant speed) + * + * @method LeanSmooth.linear (float) + * @param {float} current:float the current value + * @param {float} target:float the value we are trying to reach + * @param {float} moveSpeed:float the speed at which to move towards the target + * @param {float} deltaTime:float the difference in time since the method was called (defaults to Time.deltaTime) + * @example + * followVar = LeanSmooth.linear(followVar, destinationVar, 50f);\n + * Debug.Log("current:"+followVar); + */ + public static float linear(float current, float target, float moveSpeed, float deltaTime = -1f) + { + if (deltaTime < 0f) + deltaTime = Time.deltaTime; + + bool targetGreater = (target > current); + + float currentVelocity = deltaTime * moveSpeed * (targetGreater ? 1f : -1f); + + float returned = current + currentVelocity; + + float returnPassed = returned - target; + if ((targetGreater && returnPassed > 0) || !targetGreater && returnPassed < 0) + { // Has passed point, return target + return target; + } + + return returned; + } + + /** + * Moves one value towards another (at a constant speed) + * + * @method LeanSmooth.linear (Vector3) + * @param {Vector3} current:float the current value + * @param {Vector3} target:float the value we are trying to reach + * @param {float} moveSpeed:float the speed at which to move towards the target + * @param {float} deltaTime:float the difference in time since the method was called (defaults to Time.deltaTime) + * @example + * transform.position = LeanSmooth.linear(transform.position, followTrans.position, 50f);\n + * Debug.Log("current:"+transform.position); + */ + public static Vector3 linear(Vector3 current, Vector3 target, float moveSpeed, float deltaTime = -1f) + { + float x = linear(current.x, target.x, moveSpeed, deltaTime); + float y = linear(current.y, target.y, moveSpeed, deltaTime); + float z = linear(current.z, target.z, moveSpeed, deltaTime); + + return new Vector3(x, y, z); + } + + /** + * Moves one color towards another (at a constant speed) + * + * @method LeanSmooth.linear (Color) + * @param {Color} current:float the current value + * @param {Color} target:float the value we are trying to reach + * @param {float} moveSpeed:float the speed at which to move towards the target + * @param {float} deltaTime:float the difference in time since the method was called (defaults to Time.deltaTime) + * @example + * fromColor = LeanSmooth.linear(fromColor, transform.GetComponent().material.color, 50f);\n + * Debug.Log("current:"+fromColor); + */ + public static Color linear(Color current, Color target, float moveSpeed) + { + float r = linear(current.r, target.r, moveSpeed); + float g = linear(current.g, target.g, moveSpeed); + float b = linear(current.b, target.b, moveSpeed); + float a = linear(current.a, target.a, moveSpeed); + + return new Color(r, g, b, a); + } + + /** + * Moves one value towards another (with an ease that bounces back some when it reaches it's destination) + * + * @method LeanSmooth.bounceOut (float) + * @param {float} current:float the current value + * @param {float} target:float the value we are trying to reach + * @param {float} currentVelocity:float the current velocity of the value + * @param {float} smoothTime:float roughly the time it takes to reach the destination + * @param {float} maxSpeed:float the top speed you want the value to move at (defaults to unlimited -1f) + * @param {float} deltaTime:float the difference in time since the method was called (defaults to Time.deltaTime) + * @param {float} [friction]:float rate at which the spring is slowed down once it reaches it's destination + * @param {float} [accelRate]:float the rate it accelerates from it's initial position + * @param {float} [hitDamping]:float the rate at which to dampen the bounciness of when it reaches it's destination + * @example + * followVar = LeanSmooth.bounceOut(followVar, destinationVar, ref followVelocity, 1.1f);\n + * Debug.Log("current:"+followVar); + */ + public static float bounceOut(float current, float target, ref float currentVelocity, float smoothTime, float maxSpeed = -1f, float deltaTime = -1f, float friction = 2f, float accelRate = 0.5f, float hitDamping = 0.9f) + { + if (deltaTime < 0f) + deltaTime = Time.deltaTime; + + float diff = target - current; + + currentVelocity += deltaTime / smoothTime * accelRate * diff; + + currentVelocity *= (1f - deltaTime * friction); + + if (maxSpeed > 0f && maxSpeed < Mathf.Abs(currentVelocity)) + currentVelocity = maxSpeed * Mathf.Sign(currentVelocity); + + float returned = current + currentVelocity; + + bool targetGreater = (target > current); + float returnPassed = returned - target; + if ((targetGreater && returnPassed > 0) || !targetGreater && returnPassed < 0) + { // Start a bounce + currentVelocity = -currentVelocity * hitDamping; + returned = current + currentVelocity; + } + + return returned; + } + + /** + * Moves one value towards another (with an ease that bounces back some when it reaches it's destination) + * + * @method LeanSmooth.bounceOut (Vector3) + * @param {Vector3} current:float the current value + * @param {Vector3} target:float the value we are trying to reach + * @param {Vector3} currentVelocity:float the current velocity of the value + * @param {float} smoothTime:float roughly the time it takes to reach the destination + * @param {float} maxSpeed:float the top speed you want the value to move at (defaults to unlimited -1f) + * @param {float} deltaTime:float the difference in time since the method was called (defaults to Time.deltaTime) + * @param {float} [friction]:float rate at which the spring is slowed down once it reaches it's destination + * @param {float} [accelRate]:float the rate it accelerates from it's initial position + * @param {float} [hitDamping]:float the rate at which to dampen the bounciness of when it reaches it's destination + * @example + * transform.position = LeanSmooth.bounceOut(transform.position, followTrans.position, ref followVelocity, 1.1f);\n + * Debug.Log("current:"+transform.position); + */ + public static Vector3 bounceOut(Vector3 current, Vector3 target, ref Vector3 currentVelocity, float smoothTime, float maxSpeed = -1f, float deltaTime = -1f, float friction = 2f, float accelRate = 0.5f, float hitDamping = 0.9f) + { + float x = bounceOut(current.x, target.x, ref currentVelocity.x, smoothTime, maxSpeed, deltaTime, friction, accelRate, hitDamping); + float y = bounceOut(current.y, target.y, ref currentVelocity.y, smoothTime, maxSpeed, deltaTime, friction, accelRate, hitDamping); + float z = bounceOut(current.z, target.z, ref currentVelocity.z, smoothTime, maxSpeed, deltaTime, friction, accelRate, hitDamping); + + return new Vector3(x, y, z); + } + + /** + * Moves one color towards another (with an ease that bounces back some when it reaches it's destination) + * + * @method LeanSmooth.bounceOut (Color) + * @param {Color} current:float the current value + * @param {Color} target:float the value we are trying to reach + * @param {Color} currentVelocity:float the current velocity of the value + * @param {float} smoothTime:float roughly the time it takes to reach the destination + * @param {float} maxSpeed:float the top speed you want the value to move at (defaults to unlimited -1f) + * @param {float} deltaTime:float the difference in time since the method was called (defaults to Time.deltaTime) + * @param {float} [friction]:float rate at which the spring is slowed down once it reaches it's destination + * @param {float} [accelRate]:float the rate it accelerates from it's initial position + * @param {float} [hitDamping]:float the rate at which to dampen the bounciness of when it reaches it's destination + * @example + * fromColor = LeanSmooth.bounceOut(fromColor, transform.GetComponent().material.color, ref followVelocity, 1.1f);\n + * Debug.Log("current:" + fromColor); + */ + public static Color bounceOut(Color current, Color target, ref Color currentVelocity, float smoothTime, float maxSpeed = -1f, float deltaTime = -1f, float friction = 2f, float accelRate = 0.5f, float hitDamping = 0.9f) + { + float r = bounceOut(current.r, target.r, ref currentVelocity.r, smoothTime, maxSpeed, deltaTime, friction, accelRate, hitDamping); + float g = bounceOut(current.g, target.g, ref currentVelocity.g, smoothTime, maxSpeed, deltaTime, friction, accelRate, hitDamping); + float b = bounceOut(current.b, target.b, ref currentVelocity.b, smoothTime, maxSpeed, deltaTime, friction, accelRate, hitDamping); + float a = bounceOut(current.a, target.a, ref currentVelocity.a, smoothTime, maxSpeed, deltaTime, friction, accelRate, hitDamping); + + return new Color(r, g, b, a); + } +} diff --git a/KFAttached/LeanTween/Framework/LeanSmooth.cs.meta b/KFAttached/LeanTween/Framework/LeanSmooth.cs.meta new file mode 100644 index 0000000..4494902 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LeanSmooth.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1ca0f285af8dd4270bd759978223faad +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/LeanTween/Framework/LeanTest.cs b/KFAttached/LeanTween/Framework/LeanTest.cs new file mode 100644 index 0000000..2477135 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LeanTest.cs @@ -0,0 +1,146 @@ +using System.Collections; +using UnityEngine; + +public class LeanTester : MonoBehaviour +{ + public float timeout = 15f; + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 + public void Start() + { + StartCoroutine(timeoutCheck()); + } + + IEnumerator timeoutCheck() + { + float pauseEndTime = Time.realtimeSinceStartup + timeout; + while (Time.realtimeSinceStartup < pauseEndTime) + { + yield return 0; + } + if (LeanTest.testsFinished == false) + { + Debug.Log(LeanTest.formatB("Tests timed out!")); + LeanTest.overview(); + } + } +#endif +} + +public class LeanTest : object +{ + public static int expected = 0; + private static int tests = 0; + private static int passes = 0; + + public static float timeout = 15f; + public static bool timeoutStarted = false; + public static bool testsFinished = false; + + public static void debug(string name, bool didPass, string failExplaination = null) + { + expect(didPass, name, failExplaination); + } + + public static void expect(bool didPass, string definition, string failExplaination = null) + { + float len = printOutLength(definition); + int paddingLen = 40 - (int)(len * 1.05f); +#if UNITY_FLASH + string padding = padRight(paddingLen); +#else + string padding = "".PadRight(paddingLen, "_"[0]); +#endif + string logName = formatB(definition) + " " + padding + " [ " + (didPass ? formatC("pass", "green") : formatC("fail", "red")) + " ]"; + if (didPass == false && failExplaination != null) + logName += " - " + failExplaination; + Debug.Log(logName); + if (didPass) + passes++; + tests++; + + // Debug.Log("tests:"+tests+" expected:"+expected); + if (tests == expected && testsFinished == false) + { + overview(); + } + else if (tests > expected) + { + Debug.Log(formatB("Too many tests for a final report!") + " set LeanTest.expected = " + tests); + } + + if (timeoutStarted == false) + { + timeoutStarted = true; + GameObject tester = new GameObject(); + tester.name = "~LeanTest"; + LeanTester test = tester.AddComponent(typeof(LeanTester)) as LeanTester; + test.timeout = timeout; +#if !UNITY_EDITOR + tester.hideFlags = HideFlags.HideAndDontSave; +#endif + } + } + + public static string padRight(int len) + { + string str = ""; + for (int i = 0; i < len; i++) + { + str += "_"; + } + return str; + } + + public static float printOutLength(string str) + { + float len = 0.0f; + for (int i = 0; i < str.Length; i++) + { + if (str[i] == "I"[0]) + { + len += 0.5f; + } + else if (str[i] == "J"[0]) + { + len += 0.85f; + } + else + { + len += 1.0f; + } + } + return len; + } + + public static string formatBC(string str, string color) + { + return formatC(formatB(str), color); + } + + public static string formatB(string str) + { +#if UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 + return str; +#else + return "" + str + ""; +#endif + } + + public static string formatC(string str, string color) + { +#if UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 + return str; +#else + return "" + str + ""; +#endif + } + + public static void overview() + { + testsFinished = true; + int failedCnt = (expected - passes); + string failedStr = failedCnt > 0 ? formatBC("" + failedCnt, "red") : "" + failedCnt; + Debug.Log(formatB("Final Report:") + " _____________________ PASSED: " + formatBC("" + passes, "green") + " FAILED: " + failedStr + " "); + } +} diff --git a/KFAttached/LeanTween/Framework/LeanTest.cs.meta b/KFAttached/LeanTween/Framework/LeanTest.cs.meta new file mode 100644 index 0000000..8508b49 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LeanTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82464f26ca2ba284a8f92f51248c574a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/LeanTween/Framework/LeanTween.cs b/KFAttached/LeanTween/Framework/LeanTween.cs new file mode 100644 index 0000000..7fabca2 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LeanTween.cs @@ -0,0 +1,4581 @@ +//namespace DentedPixel{ + +// LeanTween version 2.50 - http://dentedpixel.com/developer-diary/ +// +// The MIT License (MIT) +// +// Copyright (c) 2017 Russell Savage - Dented Pixel +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + + + +/* +TERMS OF USE - EASING EQUATIONS# +Open source under the BSD License. +Copyright (c)2001 Robert Penner +All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/** +* Pass this to the "ease" parameter, to get a different easing behavior

+* Example:
LeanTween.rotateX(gameObject, 270.0f, 1.5f).setEase(LeanTweenType.easeInBack); +* +* @class LeanTweenType +*/ + +/** +* @property {integer} linear +*/ +/** +* @property {integer} easeOutQuad +*/ +/** +* @property {integer} easeInQuad +*/ +/** +* @property {integer} easeInOutQuad +*/ +/** +* @property {integer} easeInCubic +*/ +/** +* @property {integer} easeOutCubic +*/ +/** +* @property {integer} easeInOutCubic +*/ +/** +* @property {integer} easeInQuart +*/ +/** +* @property {integer} easeOutQuart +*/ +/** +* @property {integer} easeInOutQuart +*/ +/** +* @property {integer} easeInQuint +*/ +/** +* @property {integer} easeOutQuint +*/ +/** +* @property {integer} easeInOutQuint +*/ +/** +* @property {integer} easeInSine +*/ +/** +* @property {integer} easeOutSine +*/ +/** +* @property {integer} easeInOutSine +*/ +/** +* @property {integer} easeInExpo +*/ +/** +* @property {integer} easeOutExpo +*/ +/** +* @property {integer} easeInOutExpo +*/ +/** +* @property {integer} easeInCirc +*/ +/** +* @property {integer} easeOutCirc +*/ +/** +* @property {integer} easeInOutCirc +*/ +/** +* @property {integer} easeInBounce +*/ +/** +* @property {integer} easeOutBounce +*/ +/** +* @property {integer} easeInOutBounce +*/ +/** +* @property {integer} easeInBack +*/ +/** +* @property {integer} easeOutBack +*/ +/** +* @property {integer} easeInOutBack +*/ +/** +* @property {integer} easeInElastic +*/ +/** +* @property {integer} easeOutElastic +*/ +/** +* @property {integer} easeInOutElastic +*/ +/** +* @property {integer} punch +*/ +using System; +using System.Collections.Generic; +using UnityEngine; + +public enum TweenAction +{ + MOVE_X, + MOVE_Y, + MOVE_Z, + MOVE_LOCAL_X, + MOVE_LOCAL_Y, + MOVE_LOCAL_Z, + MOVE_CURVED, + MOVE_CURVED_LOCAL, + MOVE_SPLINE, + MOVE_SPLINE_LOCAL, + SCALE_X, + SCALE_Y, + SCALE_Z, + ROTATE_X, + ROTATE_Y, + ROTATE_Z, + ROTATE_AROUND, + ROTATE_AROUND_LOCAL, + CANVAS_ROTATEAROUND, + CANVAS_ROTATEAROUND_LOCAL, + CANVAS_PLAYSPRITE, + ALPHA, + TEXT_ALPHA, + CANVAS_ALPHA, + CANVASGROUP_ALPHA, + ALPHA_VERTEX, + COLOR, + CALLBACK_COLOR, + TEXT_COLOR, + CANVAS_COLOR, + CANVAS_MOVE_X, + CANVAS_MOVE_Y, + CANVAS_MOVE_Z, + CALLBACK, + MOVE, + MOVE_LOCAL, + MOVE_TO_TRANSFORM, + ROTATE, + ROTATE_LOCAL, + SCALE, + VALUE3, + GUI_MOVE, + GUI_MOVE_MARGIN, + GUI_SCALE, + GUI_ALPHA, + GUI_ROTATE, + DELAYED_SOUND, + CANVAS_MOVE, + CANVAS_SCALE, + CANVAS_SIZEDELTA, + FOLLOW, + +} + +public enum LeanTweenType +{ + notUsed, linear, easeOutQuad, easeInQuad, easeInOutQuad, easeInCubic, easeOutCubic, easeInOutCubic, easeInQuart, easeOutQuart, easeInOutQuart, + easeInQuint, easeOutQuint, easeInOutQuint, easeInSine, easeOutSine, easeInOutSine, easeInExpo, easeOutExpo, easeInOutExpo, easeInCirc, easeOutCirc, easeInOutCirc, + easeInBounce, easeOutBounce, easeInOutBounce, easeInBack, easeOutBack, easeInOutBack, easeInElastic, easeOutElastic, easeInOutElastic, easeSpring, easeShake, punch, once, clamp, pingPong, animationCurve +} + +public enum LeanProp +{ + position, + localPosition, + x, + y, + z, + localX, + localY, + localZ, + scale, + color +} + +/** +* LeanTween is an efficient tweening engine for Unity3d

+* Index of All Methods | Optional Paramaters that can be passed

+* Optional Parameters are passed at the end of every method
+*
+* Example:
+* LeanTween.moveX( gameObject, 1f, 1f).setEase( LeanTweenType.easeInQuad ).setDelay(1f);
+*
+* You can pass the optional parameters in any order, and chain on as many as you wish!

+* You can also modify this tween later, just save the unique id of the tween.
+*

Example:

+* int id = LeanTween.moveX(gameObject, 1f, 1f).id;
+* LTDescr d = LeanTween.descr( id );

+* if(d!=null){ // if the tween has already finished it will return null
+*    // change some parameters
+*    d.setOnComplete( onCompleteFunc ).setEase( LeanTweenType.easeInOutBack );
+* } +* +* @class LeanTween +*/ + +public class LeanTween : MonoBehaviour +{ + + public static bool throwErrors = true; + public static float tau = Mathf.PI * 2.0f; + public static float PI_DIV2 = Mathf.PI / 2.0f; + + private static LTSeq[] sequences; + + private static LTDescr[] tweens; + private static int[] tweensFinished; + private static int[] tweensFinishedIds; + private static LTDescr tween; + private static int tweenMaxSearch = -1; + private static int maxTweens = 400; + private static int maxSequences = 400; + private static int frameRendered = -1; + private static GameObject _tweenEmpty; + public static float dtEstimated = -1f; + public static float dtManual; +#if UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 + private static float previousRealTime; +#endif + public static float dtActual; + private static uint global_counter = 0; + private static int i; + private static int j; + private static int finishedCnt; + public static AnimationCurve punch = new AnimationCurve(new Keyframe(0.0f, 0.0f), new Keyframe(0.112586f, 0.9976035f), new Keyframe(0.3120486f, -0.1720615f), new Keyframe(0.4316337f, 0.07030682f), new Keyframe(0.5524869f, -0.03141804f), new Keyframe(0.6549395f, 0.003909959f), new Keyframe(0.770987f, -0.009817753f), new Keyframe(0.8838775f, 0.001939224f), new Keyframe(1.0f, 0.0f)); + public static AnimationCurve shake = new AnimationCurve(new Keyframe(0f, 0f), new Keyframe(0.25f, 1f), new Keyframe(0.75f, -1f), new Keyframe(1f, 0f)); + + public static void init() + { + init(maxTweens); + } + + public static int maxSearch + { + get + { + return tweenMaxSearch; + } + } + + public static int maxSimulataneousTweens + { + get + { + return maxTweens; + } + } + + /** + * Find out how many tweens you have animating at a given time + * + * @method LeanTween.tweensRunning + * @example + * Debug.Log("I have "+LeanTween.tweensRunning+" animating!"); + */ + public static int tweensRunning + { + get + { + int count = 0; + for (int i = 0; i <= tweenMaxSearch; i++) + { + if (tweens[i].toggle) + { + count++; + } + } + return count; + } + } + + /** + * This line is optional. Here you can specify the maximum number of tweens you will use (the default is 400). This must be called before any use of LeanTween is made for it to be effective. This line is optional. Here you can specify the maximum number of tweens you will use (the default is 400). This must be called before any use of LeanTween is made for it to be effective. + * + * @method LeanTween.init + * @param {integer} maxSimultaneousTweens:int The maximum number of tweens you will use, make sure you don't go over this limit, otherwise the code will throw an error + * @example + * LeanTween.init( 800 ); + */ + public static void init(int maxSimultaneousTweens) + { + init(maxSimultaneousTweens, maxSequences); + } + + public static void init(int maxSimultaneousTweens, int maxSimultaneousSequences) + { + if (tweens == null) + { + maxTweens = maxSimultaneousTweens; + tweens = new LTDescr[maxTweens]; + tweensFinished = new int[maxTweens]; + tweensFinishedIds = new int[maxTweens]; + _tweenEmpty = new GameObject(); + _tweenEmpty.name = "~LeanTween"; + _tweenEmpty.AddComponent(typeof(LeanTween)); + _tweenEmpty.isStatic = true; +#if !UNITY_EDITOR + _tweenEmpty.hideFlags = HideFlags.HideAndDontSave; +#endif +#if UNITY_EDITOR + if(Application.isPlaying) + DontDestroyOnLoad( _tweenEmpty ); +#else + DontDestroyOnLoad(_tweenEmpty); +#endif + for (int i = 0; i < maxTweens; i++) + { + tweens[i] = new LTDescr(); + } + +#if UNITY_5_4_OR_NEWER + UnityEngine.SceneManagement.SceneManager.sceneLoaded += onLevelWasLoaded54; +#endif + + sequences = new LTSeq[maxSimultaneousSequences]; + + for (int i = 0; i < maxSimultaneousSequences; i++) + { + sequences[i] = new LTSeq(); + } + } + } + + public static void reset() + { + if (tweens != null) + { + for (int i = 0; i <= tweenMaxSearch; i++) + { + if (tweens[i] != null) + tweens[i].toggle = false; + } + } + tweens = null; + Destroy(_tweenEmpty); + } + + public void Update() + { + LeanTween.update(); + } + +#if UNITY_5_4_OR_NEWER + private static void onLevelWasLoaded54( UnityEngine.SceneManagement.Scene scene, UnityEngine.SceneManagement.LoadSceneMode mode ){ internalOnLevelWasLoaded( scene.buildIndex ); } +#else + public void OnLevelWasLoaded(int lvl) { internalOnLevelWasLoaded(lvl); } +#endif + + private static void internalOnLevelWasLoaded(int lvl) + { + // Debug.Log("reseting gui"); + LTGUI.reset(); + } + + private static int maxTweenReached; + + public static void update() + { + if (frameRendered != Time.frameCount) + { // make sure update is only called once per frame + init(); + +#if UNITY_3_5 || UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 + dtEstimated = Time.realtimeSinceStartup - previousRealTime; + if(dtEstimated>0.2f) // a catch put in, when at the start sometimes this number can grow unrealistically large + dtEstimated = 0.2f; + previousRealTime = Time.realtimeSinceStartup; +#else + + dtEstimated = dtEstimated < 0f ? 0f : dtEstimated = Time.unscaledDeltaTime; + + // Debug.Log("Time.unscaledDeltaTime:"+Time.unscaledDeltaTime); +#endif + + dtActual = Time.deltaTime; + maxTweenReached = 0; + finishedCnt = 0; + // if(tweenMaxSearch>1500) + // Debug.Log("tweenMaxSearch:"+tweenMaxSearch +" maxTweens:"+maxTweens); + for (int i = 0; i <= tweenMaxSearch && i < maxTweens; i++) + { + tween = tweens[i]; + // if(i==0 && tweens[i].toggle) + // Debug.Log("tweens["+i+"]"+tweens[i]); + if (tween.toggle) + { + maxTweenReached = i; + + if (tween.updateInternal()) + { // returns true if the tween is finished with it's loop + tweensFinished[finishedCnt] = i; + tweensFinishedIds[finishedCnt] = tweens[i].id; + finishedCnt++; + } + } + } + + // Debug.Log("maxTweenReached:"+maxTweenReached); + tweenMaxSearch = maxTweenReached; + frameRendered = Time.frameCount; + + for (int i = 0; i < finishedCnt; i++) + { + j = tweensFinished[i]; + tween = tweens[j]; + + if (tween.id == tweensFinishedIds[i]) + { + // Debug.Log("removing tween:"+tween); + removeTween(j); + if (tween.hasExtraOnCompletes && tween.trans != null) + tween.callOnCompletes(); + } + } + + } + } + + + + public static void removeTween(int i, int uniqueId) + { // Only removes the tween if the unique id matches Move a GameObject to a certain location + if (tweens[i].uniqueId == uniqueId) + { + removeTween(i); + } + } + + // This method is only used internally! Do not call this from your scripts. To cancel a tween use LeanTween.cancel + public static void removeTween(int i) + { + if (tweens[i].toggle) + { + tweens[i].toggle = false; + tweens[i].counter = uint.MaxValue; + //logError("Removing tween["+i+"]:"+tweens[i]); + if (tweens[i].destroyOnComplete) + { + // Debug.Log("destroying tween.type:"+tween.type+" ltRect"+(tweens[i]._optional.ltRect==null)); + if (tweens[i]._optional.ltRect != null) + { + // Debug.Log("destroy i:"+i+" id:"+tweens[i].ltRect.id); + LTGUI.destroy(tweens[i]._optional.ltRect.id); + } + else + { // check if equal to tweenEmpty + if (tweens[i].trans != null && tweens[i].trans.gameObject != _tweenEmpty) + { + Destroy(tweens[i].trans.gameObject); + } + } + } + //tweens[i].optional = null; + startSearch = i; + //Debug.Log("start search reset:"+startSearch + " i:"+i+" tweenMaxSearch:"+tweenMaxSearch); + if (i + 1 >= tweenMaxSearch) + { + //Debug.Log("reset to zero"); + startSearch = 0; + //tweenMaxSearch--; + } + } + } + + public static Vector3[] add(Vector3[] a, Vector3 b) + { + Vector3[] c = new Vector3[a.Length]; + for (i = 0; i < a.Length; i++) + { + c[i] = a[i] + b; + } + + return c; + } + + public static float closestRot(float from, float to) + { + float minusWhole = 0 - (360 - to); + float plusWhole = 360 + to; + float toDiffAbs = Mathf.Abs(to - from); + float minusDiff = Mathf.Abs(minusWhole - from); + float plusDiff = Mathf.Abs(plusWhole - from); + if (toDiffAbs < minusDiff && toDiffAbs < plusDiff) + { + return to; + } + else + { + if (minusDiff < plusDiff) + { + return minusWhole; + } + else + { + return plusWhole; + } + } + } + + /** + * Cancels all tweens + * + * @method LeanTween.cancelAll + * @param {bool} callComplete:bool (optional) if true, then the all onCompletes will run before canceling + * @example LeanTween.cancelAll(true);
+ */ + public static void cancelAll() + { + cancelAll(false); + } + public static void cancelAll(bool callComplete) + { + init(); + for (int i = 0; i <= tweenMaxSearch; i++) + { + if (tweens[i].trans != null) + { + if (callComplete && tweens[i].optional.onComplete != null) + tweens[i].optional.onComplete(); + removeTween(i); + } + } + } + + /** + * Cancel all tweens that are currently targeting the gameObject + * + * @method LeanTween.cancel + * @param {GameObject} gameObject:GameObject gameObject whose tweens you wish to cancel + * @param {bool} callOnComplete:bool (optional) whether to call the onComplete method before canceling + * @example LeanTween.move( gameObject, new Vector3(0f,1f,2f), 1f);
+ * LeanTween.cancel( gameObject ); + */ + public static void cancel(GameObject gameObject) + { + cancel(gameObject, false); + } + public static void cancel(GameObject gameObject, bool callOnComplete) + { + init(); + Transform trans = gameObject.transform; + for (int i = 0; i <= tweenMaxSearch; i++) + { + LTDescr tween = tweens[i]; + if (tween != null && tween.toggle && tween.trans == trans) + { + if (callOnComplete && tween.optional.onComplete != null) + tween.optional.onComplete(); + removeTween(i); + } + } + } + + public static void cancel(RectTransform rect) + { + cancel(rect.gameObject, false); + } + + // public static void cancel( GameObject gameObject, int uniqueId ){ + // if(uniqueId>=0){ + // init(); + // int backId = uniqueId & 0xFFFF; + // int backCounter = uniqueId >> 16; + // // Debug.Log("uniqueId:"+uniqueId+ " id:"+backId +" counter:"+backCounter + " setCounter:"+ tweens[backId].counter + " tweens[id].type:"+tweens[backId].type); + // if(tweens[backId].trans==null || (tweens[backId].trans.gameObject == gameObject && tweens[backId].counter==backCounter)) + // removeTween((int)backId); + // } + // } + + public static void cancel(GameObject gameObject, int uniqueId, bool callOnComplete = false) + { + if (uniqueId >= 0) + { + init(); + int backId = uniqueId & 0xFFFF; + int backCounter = uniqueId >> 16; + // Debug.Log("uniqueId:"+uniqueId+ " id:"+backId +" counter:"+backCounter + " setCounter:"+ tw eens[backId].counter + " tweens[id].type:"+tweens[backId].type); + if (tweens[backId].trans == null || (tweens[backId].trans.gameObject == gameObject && tweens[backId].counter == backCounter)) + { + if (callOnComplete && tweens[backId].optional.onComplete != null) + tweens[backId].optional.onComplete(); + removeTween((int)backId); + } + } + } + + public static void cancel(LTRect ltRect, int uniqueId) + { + if (uniqueId >= 0) + { + init(); + int backId = uniqueId & 0xFFFF; + int backCounter = uniqueId >> 16; + // Debug.Log("uniqueId:"+uniqueId+ " id:"+backId +" action:"+(TweenAction)backType + " tweens[id].type:"+tweens[backId].type); + if (tweens[backId]._optional.ltRect == ltRect && tweens[backId].counter == backCounter) + removeTween((int)backId); + } + } + + /** + * Cancel a specific tween with the provided id + * + * @method LeanTween.cancel + * @param {int} id:int unique id that represents that tween + * @param {bool} callOnComplete:bool (optional) whether to call the onComplete method before canceling + * @example int id = LeanTween.move( gameObject, new Vector3(0f,1f,2f), 1f).id;
+ * LeanTween.cancel( id ); + */ + public static void cancel(int uniqueId) + { + cancel(uniqueId, false); + } + public static void cancel(int uniqueId, bool callOnComplete) + { + if (uniqueId >= 0) + { + init(); + int backId = uniqueId & 0xFFFF; + int backCounter = uniqueId >> 16; + if (backId > tweens.Length - 1) + { // sequence + int sequenceId = backId - tweens.Length; + LTSeq seq = sequences[sequenceId]; + // Debug.Log("sequenceId:" + sequenceId+" maxSequences:"+maxSequences+" prev:"+seq.previous); + + for (int i = 0; i < maxSequences; i++) + { + if (seq.current.tween != null) + { + int tweenId = seq.current.tween.uniqueId; + int tweenIndex = tweenId & 0xFFFF; + removeTween(tweenIndex); + } + if (seq.current.previous == null) + break; + seq.current = seq.current.previous; + } + } + else + { // tween + // Debug.Log("uniqueId:"+uniqueId+ " id:"+backId +" action:"+(TweenAction)backType + " tweens[id].type:"+tweens[backId].type); + if (tweens[backId].counter == backCounter) + { + if (callOnComplete && tweens[backId].optional.onComplete != null) + tweens[backId].optional.onComplete(); + removeTween((int)backId); + } + } + } + } + + /** + * Retrieve a tweens LTDescr object to modify + * + * @method LeanTween.descr + * @param {int} id:int unique id that represents that tween + * @example int id = LeanTween.move( gameObject, new Vector3(0f,1f,2f), 1f).setOnComplete( oldMethod ).id;

+ *
// later I want decide I want to change onComplete method
+ * LTDescr descr = LeanTween.descr( id );
+ * if(descr!=null) // if the tween has already finished it will come back null
+ *   descr.setOnComplete( newMethod );
+ */ + public static LTDescr descr(int uniqueId) + { + init(); + + int backId = uniqueId & 0xFFFF; + int backCounter = uniqueId >> 16; + + // Debug.Log("backId:" + backId+" backCounter:"+backCounter); + if (tweens[backId] != null && tweens[backId].uniqueId == uniqueId && tweens[backId].counter == backCounter) + { + // Debug.Log("tween count:" + tweens[backId].counter); + return tweens[backId]; + } + for (int i = 0; i <= tweenMaxSearch; i++) + { + if (tweens[i].uniqueId == uniqueId && tweens[i].counter == backCounter) + { + return tweens[i]; + } + } + return null; + } + + public static LTDescr description(int uniqueId) + { + return descr(uniqueId); + } + + /** + * Retrieve a tweens LTDescr object(s) to modify + * + * @method LeanTween.descriptions + * @param {GameObject} id:GameObject object whose tween descriptions you want to retrieve + * @example LeanTween.move( gameObject, new Vector3(0f,1f,2f), 1f).setOnComplete( oldMethod );

+ *
// later I want decide I want to change onComplete method
+ * LTDescr[] descr = LeanTween.descriptions( gameObject );
+ * if(descr.Length>0) // make sure there is a valid description for this target
+ *   descr[0].setOnComplete( newMethod );// in this case we only ever expect there to be one tween on this object
+ */ + public static LTDescr[] descriptions(GameObject gameObject = null) + { + if (gameObject == null) return null; + + List descrs = new List(); + Transform trans = gameObject.transform; + for (int i = 0; i <= tweenMaxSearch; i++) + { + if (tweens[i].toggle && tweens[i].trans == trans) + descrs.Add(tweens[i]); + } + return descrs.ToArray(); + } + + [System.Obsolete("Use 'pause( id )' instead")] + public static void pause(GameObject gameObject, int uniqueId) + { + pause(uniqueId); + } + + /** + * Pause all tweens for a GameObject + * + * @method LeanTween.pause + * @param {int} id:int Id of the tween you want to pause + * @example + * int id = LeanTween.moveX(gameObject, 5, 1.0).id
+ * LeanTween.pause( id );
+ * // Later....
+ * LeanTween.resume( id ); + */ + public static void pause(int uniqueId) + { + int backId = uniqueId & 0xFFFF; + int backCounter = uniqueId >> 16; + if (tweens[backId].counter == backCounter) + { + tweens[backId].pause(); + } + } + + /** + * Pause all tweens for a GameObject + * + * @method LeanTween.pause + * @param {GameObject} gameObject:GameObject GameObject whose tweens you want to pause + */ + public static void pause(GameObject gameObject) + { + Transform trans = gameObject.transform; + for (int i = 0; i <= tweenMaxSearch; i++) + { + if (tweens[i].trans == trans) + { + tweens[i].pause(); + } + } + } + + /** + * Pause all active tweens + * + * @method LeanTween.pauseAll + */ + public static void pauseAll() + { + init(); + for (int i = 0; i <= tweenMaxSearch; i++) + { + tweens[i].pause(); + } + } + + /** + * Resume all active tweens + * + * @method LeanTween.resumeAll + */ + public static void resumeAll() + { + init(); + for (int i = 0; i <= tweenMaxSearch; i++) + { + tweens[i].resume(); + } + } + + [System.Obsolete("Use 'resume( id )' instead")] + public static void resume(GameObject gameObject, int uniqueId) + { + resume(uniqueId); + } + + /** + * Resume a specific tween + * + * @method LeanTween.resume + * @param {int} id:int Id of the tween you want to resume + * @example + * int id = LeanTween.moveX(gameObject, 5, 1.0).id
+ * LeanTween.pause( id );
+ * // Later....
+ * LeanTween.resume( id ); + */ + public static void resume(int uniqueId) + { + int backId = uniqueId & 0xFFFF; + int backCounter = uniqueId >> 16; + if (tweens[backId].counter == backCounter) + { + tweens[backId].resume(); + } + } + + /** + * Resume all the tweens on a GameObject + * + * @method LeanTween.resume + * @param {GameObject} gameObject:GameObject GameObject whose tweens you want to resume + */ + public static void resume(GameObject gameObject) + { + Transform trans = gameObject.transform; + for (int i = 0; i <= tweenMaxSearch; i++) + { + if (tweens[i].trans == trans) + tweens[i].resume(); + } + } + + /** + * Test whether or not a tween is paused on a GameObject + * + * @method LeanTween.isPaused + * @param {GameObject} gameObject:GameObject GameObject that you want to test if it is paused + */ + public static bool isPaused(GameObject gameObject = null) + { + if (gameObject == null) + { + for (int i = 0; i <= tweenMaxSearch; i++) + { + if (Mathf.Equals(tweens[i].direction, 0f)) + return true; + } + return false; + } + Transform trans = gameObject.transform; + for (int i = 0; i <= tweenMaxSearch; i++) + { + if (Mathf.Equals(tweens[i].direction, 0f) && tweens[i].trans == trans) + return true; + } + return false; + } + + public static bool isPaused(RectTransform rect) + { + return isTweening(rect.gameObject); + } + + /** + * Test whether or not a tween is paused or not + * + * @method LeanTween.isPaused + * @param {GameObject} id:int id of the tween that you want to test if it is paused + * @example + * int id = LeanTween.moveX(gameObject, 1f, 3f).id;
+ * LeanTween.pause(gameObject);
+ * if(LeanTween.isPaused( id ))
+ *      Debug.Log("I am paused!");
+ */ + public static bool isPaused(int uniqueId) + { + int backId = uniqueId & 0xFFFF; + int backCounter = uniqueId >> 16; + if (backId < 0 || backId >= maxTweens) return false; + // Debug.Log("tweens[backId].counter:"+tweens[backId].counter+" backCounter:"+backCounter +" toggle:"+tweens[backId].toggle); + if (tweens[backId].counter == backCounter && Mathf.Equals(tweens[i].direction, 0f)) + { + return true; + } + return false; + } + + /** + * Test whether or not a tween is active on a GameObject + * + * @method LeanTween.isTweening + * @param {GameObject} gameObject:GameObject GameObject that you want to test if it is tweening + */ + public static bool isTweening(GameObject gameObject = null) + { + if (gameObject == null) + { + for (int i = 0; i <= tweenMaxSearch; i++) + { + if (tweens[i].toggle) + return true; + } + return false; + } + Transform trans = gameObject.transform; + for (int i = 0; i <= tweenMaxSearch; i++) + { + if (tweens[i].toggle && tweens[i].trans == trans) + return true; + } + return false; + } + + public static bool isTweening(RectTransform rect) + { + return isTweening(rect.gameObject); + } + + /** + * Test whether or not a tween is active or not + * + * @method LeanTween.isTweening + * @param {GameObject} id:int id of the tween that you want to test if it is tweening + * @example + * int id = LeanTween.moveX(gameObject, 1f, 3f).id;
+ * if(LeanTween.isTweening( id ))
+ *      Debug.Log("I am tweening!");
+ */ + public static bool isTweening(int uniqueId) + { + int backId = uniqueId & 0xFFFF; + int backCounter = uniqueId >> 16; + if (backId < 0 || backId >= maxTweens) return false; + // Debug.Log("tweens[backId].counter:"+tweens[backId].counter+" backCounter:"+backCounter +" toggle:"+tweens[backId].toggle); + if (tweens[backId].counter == backCounter && tweens[backId].toggle) + { + return true; + } + return false; + } + + public static bool isTweening(LTRect ltRect) + { + for (int i = 0; i <= tweenMaxSearch; i++) + { + if (tweens[i].toggle && tweens[i]._optional.ltRect == ltRect) + return true; + } + return false; + } + + public static void drawBezierPath(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float arrowSize = 0.0f, Transform arrowTransform = null) + { + Vector3 last = a; + Vector3 p; + Vector3 aa = (-a + 3 * (b - c) + d); + Vector3 bb = 3 * (a + c) - 6 * b; + Vector3 cc = 3 * (b - a); + + float t; + + if (arrowSize > 0.0f) + { + Vector3 beforePos = arrowTransform.position; + Quaternion beforeQ = arrowTransform.rotation; + float distanceTravelled = 0f; + + for (float k = 1.0f; k <= 120.0f; k++) + { + t = k / 120.0f; + p = ((aa * t + (bb)) * t + cc) * t + a; + Gizmos.DrawLine(last, p); + distanceTravelled += (p - last).magnitude; + if (distanceTravelled > 1f) + { + distanceTravelled = distanceTravelled - 1f; + /*float deltaY = p.y - last.y; + float deltaX = p.x - last.x; + float ang = Mathf.Atan(deltaY / deltaX); + Vector3 arrow = p + new Vector3( Mathf.Cos(ang+2.5f), Mathf.Sin(ang+2.5f), 0f)*0.5f; + Gizmos.DrawLine(p, arrow); + arrow = p + new Vector3( Mathf.Cos(ang+-2.5f), Mathf.Sin(ang+-2.5f), 0f)*0.5f; + Gizmos.DrawLine(p, arrow);*/ + + arrowTransform.position = p; + arrowTransform.LookAt(last, Vector3.forward); + Vector3 to = arrowTransform.TransformDirection(Vector3.right); + // Debug.Log("to:"+to+" tweenEmpty.transform.position:"+arrowTransform.position); + Vector3 back = (last - p); + back = back.normalized; + Gizmos.DrawLine(p, p + (to + back) * arrowSize); + to = arrowTransform.TransformDirection(-Vector3.right); + Gizmos.DrawLine(p, p + (to + back) * arrowSize); + } + last = p; + } + + arrowTransform.position = beforePos; + arrowTransform.rotation = beforeQ; + } + else + { + for (float k = 1.0f; k <= 30.0f; k++) + { + t = k / 30.0f; + p = ((aa * t + (bb)) * t + cc) * t + a; + Gizmos.DrawLine(last, p); + last = p; + } + } + } + + public static object logError(string error) + { + if (throwErrors) Debug.LogError(error); else Debug.Log(error); + return null; + } + + public static LTDescr options(LTDescr seed) { Debug.LogError("error this function is no longer used"); return null; } + public static LTDescr options() + { + init(); + + bool found = false; + // Debug.Log("Search start"); + for (j = 0, i = startSearch; j <= maxTweens; i++) + { + if (j >= maxTweens) + return logError("LeanTween - You have run out of available spaces for tweening. To avoid this error increase the number of spaces to available for tweening when you initialize the LeanTween class ex: LeanTween.init( " + (maxTweens * 2) + " );") as LTDescr; + if (i >= maxTweens) + i = 0; + // Debug.Log("searching i:"+i); + if (tweens[i].toggle == false) + { + if (i + 1 > tweenMaxSearch && i + 1 < maxTweens) + tweenMaxSearch = i + 1; + startSearch = i + 1; + found = true; + break; + } + + j++; + } + if (found == false) + logError("no available tween found!"); + + // Debug.Log("new tween with i:"+i+" counter:"+tweens[i].counter+" tweenMaxSearch:"+tweenMaxSearch+" tween:"+tweens[i]); + tweens[i].reset(); + + global_counter++; + if (global_counter > 0x8000) + global_counter = 0; + + tweens[i].setId((uint)i, global_counter); + + return tweens[i]; + } + + + public static GameObject tweenEmpty + { + get + { + init(maxTweens); + return _tweenEmpty; + } + } + + public static int startSearch = 0; + public static LTDescr d; + + private static LTDescr pushNewTween(GameObject gameObject, Vector3 to, float time, LTDescr tween) + { + init(maxTweens); + if (gameObject == null || tween == null) + return null; + + tween.trans = gameObject.transform; + tween.to = to; + tween.time = time; + + if (tween.time <= 0f) + tween.updateInternal(); + //tween.hasPhysics = gameObject.rigidbody!=null; + + return tween; + } + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 + /** + * Play a sequence of images on a Unity UI Object + * + * @method LeanTween.play + * @param {RectTransform} rectTransform:RectTransform RectTransform that you want to play the sequence of sprites on + * @param {Sprite[]} sprites:Sprite[] Sequence of sprites to be played + * @return {LTDescr} LTDescr an object that distinguishes the tween
+ * @example + * LeanTween.play(gameObject.GetComponent<RectTransform>(), sprites).setLoopPingPong(); + */ + public static LTDescr play(RectTransform rectTransform, UnityEngine.Sprite[] sprites) + { + float defaultFrameRate = 0.25f; + float time = defaultFrameRate * sprites.Length; + return pushNewTween(rectTransform.gameObject, new Vector3((float)sprites.Length - 1.0f, 0, 0), time, options().setCanvasPlaySprite().setSprites(sprites).setRepeat(-1)); + } +#endif + + + /** + * Retrieve a sequencer object where you can easily chain together tweens and methods one after another + * + * @method LeanTween.sequence + * @return {LTSeq} LTSeq an object that you can add tweens, methods and time on to + * @example + * var seq = LeanTween.sequence();
+ * seq.add(1f); // delay everything one second
+ * seq.add( () => { // fire an event before start
+ *  Debug.Log("I have started");
+ * });
+ * seq.add( LeanTween.move(cube1, Vector3.one * 10f, 1f) ); // do a tween
+ * seq.add( () => { // fire event after tween
+ *  Debug.Log("We are done now");
+ * });;
+ */ + public static LTSeq sequence(bool initSequence = true) + { + init(maxTweens); + // Loop through and find available sequence + for (int i = 0; i < sequences.Length; i++) + { + // Debug.Log("i:" + i + " sequences[i]:" + sequences[i]); + if (sequences[i].tween == null || sequences[i].tween.toggle == false) + { + if (sequences[i].toggle == false) + { + LTSeq seq = sequences[i]; + if (initSequence) + { + seq.init((uint)(i + tweens.Length), global_counter); + + global_counter++; + if (global_counter > 0x8000) + global_counter = 0; + } + else + { + seq.reset(); + } + + return seq; + } + } + } + + return null; + } + + /** + * Fade a gameobject's material to a certain alpha value. + * + * @method LeanTween.alpha + * @param {GameObject} gameObject:GameObject Gameobject that you wish to fade + * @param {float} to:float the final alpha value (0-1) + * @param {float} time:float The time with which to fade the object + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.alpha(gameObject, 1f, 1f) .setDelay(1f); + */ + public static LTDescr alpha(GameObject gameObject, float to, float time) + { + LTDescr lt = pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setAlpha()); + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 + SpriteRenderer ren = gameObject.GetComponent(); + lt.spriteRen = ren; +#endif + return lt; + } + + /** + * Fade a GUI Object + * + * @method LeanTween.alpha + * @param {LTRect} ltRect:LTRect LTRect that you wish to fade + * @param {float} to:float the final alpha value (0-1) + * @param {float} time:float The time with which to fade the object + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.alpha(ltRect, 1f, 1f) .setEase(LeanTweenType.easeInCirc); + */ + public static LTDescr alpha(LTRect ltRect, float to, float time) + { + ltRect.alphaEnabled = true; + return pushNewTween(tweenEmpty, new Vector3(to, 0f, 0f), time, options().setGUIAlpha().setRect(ltRect)); + } + + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 + /** + * Fade a Unity UI Object + * + * @method LeanTween.alphaText + * @param {RectTransform} rectTransform:RectTransform RectTransform associated with the Text Component you wish to fade + * @param {float} to:float the final alpha value (0-1) + * @param {float} time:float The time with which to fade the object + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.alphaText(gameObject.GetComponent<RectTransform>(), 1f, 1f) .setEase(LeanTweenType.easeInCirc); + */ + public static LTDescr textAlpha(RectTransform rectTransform, float to, float time) + { + return pushNewTween(rectTransform.gameObject, new Vector3(to, 0, 0), time, options().setTextAlpha()); + } + public static LTDescr alphaText(RectTransform rectTransform, float to, float time) + { + return pushNewTween(rectTransform.gameObject, new Vector3(to, 0, 0), time, options().setTextAlpha()); + } + + /** + * Fade a Unity UI Canvas Group + * + * @method LeanTween.alphaCanvas + * @param {RectTransform} rectTransform:RectTransform RectTransform that the CanvasGroup is attached to + * @param {float} to:float the final alpha value (0-1) + * @param {float} time:float The time with which to fade the object + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.alphaCanvas(gameObject.GetComponent<RectTransform>(), 0f, 1f) .setLoopPingPong(); + */ + public static LTDescr alphaCanvas(CanvasGroup canvasGroup, float to, float time) + { + return pushNewTween(canvasGroup.gameObject, new Vector3(to, 0, 0), time, options().setCanvasGroupAlpha()); + } +#endif + + /** + * This works by tweening the vertex colors directly +
+ Vertex-based coloring is useful because you avoid making a copy of your + object's material for each instance that needs a different color.
+
+ A shader that supports vertex colors is required for it to work + (for example the shaders in Mobile/Particles/) + * + * @method LeanTween.alphaVertex + * @param {GameObject} gameObject:GameObject Gameobject that you wish to alpha + * @param {float} to:float The alpha value you wish to tween to + * @param {float} time:float The time with which to delay before calling the function + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr alphaVertex(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0f, 0f), time, options().setAlphaVertex()); + } + + /** + * Change a gameobject's material to a certain color value + * + * @method LeanTween.color + * @param {GameObject} gameObject:GameObject Gameobject that you wish to change the color + * @param {Color} to:Color the final color value ex: Color.Red, new Color(1.0f,1.0f,0.0f,0.8f) + * @param {float} time:float The time with which to fade the object + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.color(gameObject, Color.yellow, 1f) .setDelay(1f); + */ + public static LTDescr color(GameObject gameObject, Color to, float time) + { + LTDescr lt = pushNewTween(gameObject, new Vector3(1.0f, to.a, 0.0f), time, options().setColor().setPoint(new Vector3(to.r, to.g, to.b))); +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 + SpriteRenderer ren = gameObject.GetComponent(); + lt.spriteRen = ren; +#endif + return lt; + } + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 + /** + * Change the color a Unity UI Object + * + * @method LeanTween.colorText + * @param {RectTransform} rectTransform:RectTransform RectTransform attached to the Text Component whose color you want to change + * @param {Color} to:Color the final alpha value ex: Color.Red, new Color(1.0f,1.0f,0.0f,0.8f) + * @param {float} time:float The time with which to fade the object + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * LeanTween.colorText(gameObject.GetComponent<RectTransform>(), Color.yellow, 1f) .setDelay(1f); + */ + public static LTDescr textColor(RectTransform rectTransform, Color to, float time) + { + return pushNewTween(rectTransform.gameObject, new Vector3(1.0f, to.a, 0.0f), time, options().setTextColor().setPoint(new Vector3(to.r, to.g, to.b))); + } + public static LTDescr colorText(RectTransform rectTransform, Color to, float time) + { + return pushNewTween(rectTransform.gameObject, new Vector3(1.0f, to.a, 0.0f), time, options().setTextColor().setPoint(new Vector3(to.r, to.g, to.b))); + } +#endif + + /** + * Call a method after a specified amount of time + * + * @method LeanTween.delayedCall + * @param {GameObject} gameObject:GameObject Gameobject that you wish to associate with this delayed call + * @param {float} time:float delay The time you wish to pass before the method is called + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.delayedCall(gameObject, 1f, ()=>{
Debug.Log("I am called one second later!");
})); + */ + public static LTDescr delayedCall(float delayTime, Action callback) + { + return pushNewTween(tweenEmpty, Vector3.zero, delayTime, options().setCallback().setOnComplete(callback)); + } + + public static LTDescr delayedCall(float delayTime, Action callback) + { + return pushNewTween(tweenEmpty, Vector3.zero, delayTime, options().setCallback().setOnComplete(callback)); + } + + public static LTDescr delayedCall(GameObject gameObject, float delayTime, Action callback) + { + return pushNewTween(gameObject, Vector3.zero, delayTime, options().setCallback().setOnComplete(callback)); + } + + public static LTDescr delayedCall(GameObject gameObject, float delayTime, Action callback) + { + return pushNewTween(gameObject, Vector3.zero, delayTime, options().setCallback().setOnComplete(callback)); + } + + public static LTDescr destroyAfter(LTRect rect, float delayTime) + { + return pushNewTween(tweenEmpty, Vector3.zero, delayTime, options().setCallback().setRect(rect).setDestroyOnComplete(true)); + } + + /*public static LTDescr delayedCall(GameObject gameObject, float delayTime, string callback){ + return pushNewTween( gameObject, Vector3.zero, delayTime, TweenAction.CALLBACK, options().setOnComplete( callback ) ); + }*/ + + + /** + * Move a GameObject to a certain location + * + * @method LeanTween.move + * @param {GameObject} gameObject:GameObject Gameobject that you wish to move + * @param {Vector3} vec:Vector3 to The final positin with which to move to + * @param {float} time:float time The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.move(gameObject, new Vector3(0f,-3f,5f), 2.0f) .setEase( LeanTweenType.easeOutQuad ); + */ + public static LTDescr move(GameObject gameObject, Vector3 to, float time) + { + return pushNewTween(gameObject, to, time, options().setMove()); + } + public static LTDescr move(GameObject gameObject, Vector2 to, float time) + { + return pushNewTween(gameObject, new Vector3(to.x, to.y, gameObject.transform.position.z), time, options().setMove()); + } + + + /** + * Move a GameObject along a set of bezier curves + * + * @method LeanTween.move + * @param {GameObject} gameObject:GameObject Gameobject that you wish to move + * @param {Vector3[]} path:Vector3[] A set of points that define the curve(s) ex: Point1,Handle2,Handle1,Point2,... + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Javascript:
+ * LeanTween.move(gameObject, [Vector3(0,0,0),Vector3(1,0,0),Vector3(1,0,0),Vector3(1,0,1)], 2.0) .setEase(LeanTweenType.easeOutQuad).setOrientToPath(true);

+ * C#:
+ * LeanTween.move(gameObject, new Vector3[]{new Vector3(0f,0f,0f),new Vector3(1f,0f,0f),new Vector3(1f,0f,0f),new Vector3(1f,0f,1f)}, 1.5f).setEase(LeanTweenType.easeOutQuad).setOrientToPath(true);;
+ */ + public static LTDescr move(GameObject gameObject, Vector3[] to, float time) + { + d = options().setMoveCurved(); + if (d.optional.path == null) + d.optional.path = new LTBezierPath(to); + else + d.optional.path.setPoints(to); + + return pushNewTween(gameObject, new Vector3(1.0f, 0.0f, 0.0f), time, d); + } + + public static LTDescr move(GameObject gameObject, LTBezierPath to, float time) + { + d = options().setMoveCurved(); + d.optional.path = to; + + return pushNewTween(gameObject, new Vector3(1.0f, 0.0f, 0.0f), time, d); + } + + public static LTDescr move(GameObject gameObject, LTSpline to, float time) + { + d = options().setMoveSpline(); + d.optional.spline = to; + + return pushNewTween(gameObject, new Vector3(1.0f, 0.0f, 0.0f), time, d); + } + + /** + * Move a GameObject through a set of points + * + * @method LeanTween.moveSpline + * @param {GameObject} gameObject:GameObject Gameobject that you wish to move + * @param {Vector3[]} path:Vector3[] A set of points that define the curve(s) ex: ControlStart,Pt1,Pt2,Pt3,.. ..ControlEnd
Note: The first and last item just define the angle of the end points, they are not actually used in the spline path itself. If you do not care about the angle you can jus set the first two items and last two items as the same value. + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Javascript:
+ * LeanTween.moveSpline(gameObject, [Vector3(0,0,0),Vector3(1,0,0),Vector3(1,0,0),Vector3(1,0,1)], 2.0) .setEase(LeanTweenType.easeOutQuad).setOrientToPath(true);

+ * C#:
+ * LeanTween.moveSpline(gameObject, new Vector3[]{new Vector3(0f,0f,0f),new Vector3(1f,0f,0f),new Vector3(1f,0f,0f),new Vector3(1f,0f,1f)}, 1.5f).setEase(LeanTweenType.easeOutQuad).setOrientToPath(true);
+ */ + public static LTDescr moveSpline(GameObject gameObject, Vector3[] to, float time) + { + d = options().setMoveSpline(); + d.optional.spline = new LTSpline(to); + + return pushNewTween(gameObject, new Vector3(1.0f, 0.0f, 0.0f), time, d); + } + + /** + * Move a GameObject through a set of points + * + * @method LeanTween.moveSpline + * @param {GameObject} gameObject:GameObject Gameobject that you wish to move + * @param {LTSpline} spline:LTSpline pass a pre-existing LTSpline for the object to move along + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Javascript:
+ * LeanTween.moveSpline(gameObject, ltSpline, 2.0) .setEase(LeanTweenType.easeOutQuad).setOrientToPath(true);

+ * C#:
+ * LeanTween.moveSpline(gameObject, ltSpline, 1.5f).setEase(LeanTweenType.easeOutQuad).setOrientToPath(true);
+ */ + public static LTDescr moveSpline(GameObject gameObject, LTSpline to, float time) + { + d = options().setMoveSpline(); + d.optional.spline = to; + + return pushNewTween(gameObject, new Vector3(1.0f, 0.0f, 0.0f), time, d); + } + + /** + * Move a GameObject through a set of points, in local space + * + * @method LeanTween.moveSplineLocal + * @param {GameObject} gameObject:GameObject Gameobject that you wish to move + * @param {Vector3[]} path:Vector3[] A set of points that define the curve(s) ex: ControlStart,Pt1,Pt2,Pt3,.. ..ControlEnd + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Javascript:
+ * LeanTween.moveSpline(gameObject, [Vector3(0,0,0),Vector3(1,0,0),Vector3(1,0,0),Vector3(1,0,1)], 2.0) .setEase(LeanTweenType.easeOutQuad).setOrientToPath(true);

+ * C#:
+ * LeanTween.moveSpline(gameObject, new Vector3[]{new Vector3(0f,0f,0f),new Vector3(1f,0f,0f),new Vector3(1f,0f,0f),new Vector3(1f,0f,1f)}, 1.5f).setEase(LeanTweenType.easeOutQuad).setOrientToPath(true);
+ */ + public static LTDescr moveSplineLocal(GameObject gameObject, Vector3[] to, float time) + { + d = options().setMoveSplineLocal(); + d.optional.spline = new LTSpline(to); + + return pushNewTween(gameObject, new Vector3(1.0f, 0.0f, 0.0f), time, d); + } + + /** + * Move a GUI Element to a certain location + * + * @method LeanTween.move (GUI) + * @param {LTRect} ltRect:LTRect ltRect LTRect object that you wish to move + * @param {Vector2} vec:Vector2 to The final position with which to move to (pixel coordinates) + * @param {float} time:float time The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr move(LTRect ltRect, Vector2 to, float time) + { + return pushNewTween(tweenEmpty, to, time, options().setGUIMove().setRect(ltRect)); + } + + public static LTDescr moveMargin(LTRect ltRect, Vector2 to, float time) + { + return pushNewTween(tweenEmpty, to, time, options().setGUIMoveMargin().setRect(ltRect)); + } + + /** + * Move a GameObject along the x-axis + * + * @method LeanTween.moveX + * @param {GameObject} gameObject:GameObject gameObject Gameobject that you wish to move + * @param {float} to:float to The final position with which to move to + * @param {float} time:float time The time to complete the move in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr moveX(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setMoveX()); + } + + /** + * Move a GameObject along the y-axis + * + * @method LeanTween.moveY + * @param {GameObject} GameObject gameObject Gameobject that you wish to move + * @param {float} float to The final position with which to move to + * @param {float} float time The time to complete the move in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr moveY(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setMoveY()); + } + + /** + * Move a GameObject along the z-axis + * + * @method LeanTween.moveZ + * @param {GameObject} GameObject gameObject Gameobject that you wish to move + * @param {float} float to The final position with which to move to + * @param {float} float time The time to complete the move in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr moveZ(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setMoveZ()); + } + + /** + * Move a GameObject to a certain location relative to the parent transform. + * + * @method LeanTween.moveLocal + * @param {GameObject} GameObject gameObject Gameobject that you wish to rotate + * @param {Vector3} Vector3 to The final positin with which to move to + * @param {float} float time The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr moveLocal(GameObject gameObject, Vector3 to, float time) + { + return pushNewTween(gameObject, to, time, options().setMoveLocal()); + } + + /** + * Move a GameObject along a set of bezier curves, in local space + * + * @method LeanTween.moveLocal + * @param {GameObject} gameObject:GameObject Gameobject that you wish to move + * @param {Vector3[]} path:Vector3[] A set of points that define the curve(s) ex: Point1,Handle1,Handle2,Point2,... + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Javascript:
+ * LeanTween.moveLocal(gameObject, [Vector3(0,0,0),Vector3(1,0,0),Vector3(1,0,0),Vector3(1,0,1)], 2.0).setEase(LeanTweenType.easeOutQuad).setOrientToPath(true);

+ * C#:
+ * LeanTween.moveLocal(gameObject, new Vector3[]{Vector3(0f,0f,0f),Vector3(1f,0f,0f),Vector3(1f,0f,0f),Vector3(1f,0f,1f)}).setEase(LeanTweenType.easeOutQuad).setOrientToPath(true);
+ */ + public static LTDescr moveLocal(GameObject gameObject, Vector3[] to, float time) + { + d = options().setMoveCurvedLocal(); + if (d.optional.path == null) + d.optional.path = new LTBezierPath(to); + else + d.optional.path.setPoints(to); + + return pushNewTween(gameObject, new Vector3(1.0f, 0.0f, 0.0f), time, d); + } + + public static LTDescr moveLocalX(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setMoveLocalX()); + } + + public static LTDescr moveLocalY(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setMoveLocalY()); + } + + public static LTDescr moveLocalZ(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setMoveLocalZ()); + } + + public static LTDescr moveLocal(GameObject gameObject, LTBezierPath to, float time) + { + d = options().setMoveCurvedLocal(); + d.optional.path = to; + + return pushNewTween(gameObject, new Vector3(1.0f, 0.0f, 0.0f), time, d); + } + public static LTDescr moveLocal(GameObject gameObject, LTSpline to, float time) + { + d = options().setMoveSplineLocal(); + d.optional.spline = to; + + return pushNewTween(gameObject, new Vector3(1.0f, 0.0f, 0.0f), time, d); + } + + /** + * Move a GameObject to another transform + * + * @method LeanTween.move + * @param {GameObject} gameObject:GameObject Gameobject that you wish to move + * @param {Transform} destination:Transform Transform whose position the tween will finally end on + * @param {float} time:float time The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.move(gameObject, anotherTransform, 2.0f) .setEase( LeanTweenType.easeOutQuad ); + */ + public static LTDescr move(GameObject gameObject, Transform to, float time) + { + return pushNewTween(gameObject, Vector3.zero, time, options().setTo(to).setMoveToTransform()); + } + + /** + * Rotate a GameObject, to values are in passed in degrees + * + * @method LeanTween.rotate + * @param {GameObject} GameObject gameObject Gameobject that you wish to rotate + * @param {Vector3} Vector3 to The final rotation with which to rotate to + * @param {float} float time The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.rotate(cube, new Vector3(180f,30f,0f), 1.5f); + */ + + public static LTDescr rotate(GameObject gameObject, Vector3 to, float time) + { + return pushNewTween(gameObject, to, time, options().setRotate()); + } + + /** + * Rotate a GUI element (using an LTRect object), to a value that is in degrees + * + * @method LeanTween.rotate + * @param {LTRect} ltRect:LTRect LTRect that you wish to rotate + * @param {float} to:float The final rotation with which to rotate to + * @param {float} time:float The time to complete the tween in + * @param {Array} optional:Array Object Array where you can pass optional items. + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * if(GUI.Button(buttonRect.rect, "Rotate"))
+ * LeanTween.rotate( buttonRect4, 150.0f, 1.0f).setEase(LeanTweenType.easeOutElastic);
+ * GUI.matrix = Matrix4x4.identity;
+ */ + public static LTDescr rotate(LTRect ltRect, float to, float time) + { + return pushNewTween(tweenEmpty, new Vector3(to, 0f, 0f), time, options().setGUIRotate().setRect(ltRect)); + } + + /** + * Rotate a GameObject in the objects local space (on the transforms localEulerAngles object) + * + * @method LeanTween.rotateLocal + * @param {GameObject} gameObject:GameObject Gameobject that you wish to rotate + * @param {Vector3} to:Vector3 The final rotation with which to rotate to + * @param {float} time:float The time to complete the rotation in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr rotateLocal(GameObject gameObject, Vector3 to, float time) + { + return pushNewTween(gameObject, to, time, options().setRotateLocal()); + } + + /** + * Rotate a GameObject only on the X axis Rotate a GameObject only on the X axis + * + * @method LeanTween.rotateX + * @param {GameObject} GameObject Gameobject that you wish to rotate + * @param {float} to:float The final x-axis rotation with which to rotate + * @param {float} time:float The time to complete the rotation in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr rotateX(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setRotateX()); + } + + /** + * Rotate a GameObject only on the Y axis + * + * @method LeanTween.rotateY + * @param {GameObject} GameObject Gameobject that you wish to rotate + * @param {float} to:float The final y-axis rotation with which to rotate + * @param {float} time:float The time to complete the rotation in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr rotateY(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setRotateY()); + } + + /** + * Rotate a GameObject only on the Z axis + * + * @method LeanTween.rotateZ + * @param {GameObject} GameObject Gameobject that you wish to rotate + * @param {float} to:float The final z-axis rotation with which to rotate + * @param {float} time:float The time to complete the rotation in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr rotateZ(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setRotateZ()); + } + + /** + * Rotate a GameObject around a certain Axis (the best method to use when you want to rotate beyond 180 degrees) + * + * @method LeanTween.rotateAround + * @param {GameObject} gameObject:GameObject Gameobject that you wish to rotate + * @param {Vector3} vec:Vector3 axis in which to rotate around ex: Vector3.up + * @param {float} degrees:float the degrees in which to rotate + * @param {float} time:float time The time to complete the rotation in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Example:
+ * LeanTween.rotateAround ( gameObject, Vector3.left, 90f, 1f ); + */ + public static LTDescr rotateAround(GameObject gameObject, Vector3 axis, float add, float time) + { + return pushNewTween(gameObject, new Vector3(add, 0f, 0f), time, options().setAxis(axis).setRotateAround()); + } + + /** + * Rotate a GameObject around a certain Axis in Local Space (the best method to use when you want to rotate beyond 180 degrees) + * + * @method LeanTween.rotateAroundLocal + * @param {GameObject} gameObject:GameObject Gameobject that you wish to rotate + * @param {Vector3} vec:Vector3 axis in which to rotate around ex: Vector3.up + * @param {float} degrees:float the degrees in which to rotate + * @param {float} time:float time The time to complete the rotation in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Example:
+ * LeanTween.rotateAround ( gameObject, Vector3.left, 90f, 1f ); + */ + public static LTDescr rotateAroundLocal(GameObject gameObject, Vector3 axis, float add, float time) + { + return pushNewTween(gameObject, new Vector3(add, 0f, 0f), time, options().setRotateAroundLocal().setAxis(axis)); + } + + /** + * Scale a GameObject to a certain size + * + * @method LeanTween.scale + * @param {GameObject} gameObject:GameObject gameObject Gameobject that you wish to scale + * @param {Vector3} vec:Vector3 to The size with which to tween to + * @param {float} time:float time The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr scale(GameObject gameObject, Vector3 to, float time) + { + return pushNewTween(gameObject, to, time, options().setScale()); + } + + /** + * Scale a GUI Element to a certain width and height + * + * @method LeanTween.scale (GUI) + * @param {LTRect} LTRect ltRect LTRect object that you wish to move + * @param {Vector2} Vector2 to The final width and height to scale to (pixel based) + * @param {float} float time The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Example Javascript:
+ * var bRect:LTRect = new LTRect( 0, 0, 100, 50 );
+ * LeanTween.scale( bRect, Vector2(bRect.rect.width, bRect.rect.height) * 1.3, 0.25 ).setEase(LeanTweenType.easeOutBounce);
+ * function OnGUI(){
+ *   if(GUI.Button(bRect.rect, "Scale")){ }
+ * }
+ *
+ * Example C#:
+ * LTRect bRect = new LTRect( 0f, 0f, 100f, 50f );
+ * LeanTween.scale( bRect, new Vector2(150f,75f), 0.25f ).setEase(LeanTweenType.easeOutBounce);
+ * void OnGUI(){
+ *   if(GUI.Button(bRect.rect, "Scale")){ }
+ * }
+ */ + public static LTDescr scale(LTRect ltRect, Vector2 to, float time) + { + return pushNewTween(tweenEmpty, to, time, options().setGUIScale().setRect(ltRect)); + } + + /** + * Scale a GameObject to a certain size along the x-axis only + * + * @method LeanTween.scaleX + * @param {GameObject} gameObject:GameObject Gameobject that you wish to scale + * @param {float} scaleTo:float the size with which to scale to + * @param {float} time:float the time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr scaleX(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setScaleX()); + } + + /** + * Scale a GameObject to a certain size along the y-axis only + * + * @method LeanTween.scaleY + * @param {GameObject} gameObject:GameObject Gameobject that you wish to scale + * @param {float} scaleTo:float the size with which to scale to + * @param {float} time:float the time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr scaleY(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setScaleY()); + } + + /** + * Scale a GameObject to a certain size along the z-axis only + * + * @method LeanTween.scaleZ + * @param {GameObject} gameObject:GameObject Gameobject that you wish to scale + * @param {float} scaleTo:float the size with which to scale to + * @param {float} time:float the time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr scaleZ(GameObject gameObject, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setScaleZ()); + } + + /** + * Tween any particular value (float) + * + * @method LeanTween.value (float) + * @param {GameObject} gameObject:GameObject Gameobject that you wish to attach the tween to + * @param {float} from:float The original value to start the tween from + * @param {Vector3} to:float The final float with which to tween to + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Example Javascript:
+ * LeanTween.value( gameObject, 1f, 5f, 5f).setOnUpdate( function( val:float ){
+ *  Debug.Log("tweened val:"+val);
+ * } );
+ *
+ * Example C#:
+ * LeanTween.value( gameObject, 1f, 5f, 5f).setOnUpdate( (float val)=>{
+ *  Debug.Log("tweened val:"+val);
+ * } );
+ */ + public static LTDescr value(GameObject gameObject, float from, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setCallback().setFrom(new Vector3(from, 0, 0))); + } + public static LTDescr value(float from, float to, float time) + { + return pushNewTween(tweenEmpty, new Vector3(to, 0, 0), time, options().setCallback().setFrom(new Vector3(from, 0, 0))); + } + + /** + * Tween any particular value (Vector2) + * + * @method LeanTween.value (Vector2) + * @param {GameObject} gameObject:GameObject Gameobject that you wish to attach the tween to + * @param {Vector2} from:Vector2 The original value to start the tween from + * @param {Vector3} to:Vector2 The final Vector2 with which to tween to + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Example Javascript:
+ * LeanTween.value( gameObject, new Vector2(1f,0f), new Vector3(5f,0f), 5f).setOnUpdate( function( val:Vector2 ){
+ *  Debug.Log("tweened val:"+val);
+ * } );
+ *
+ * Example C#:
+ * LeanTween.value( gameObject, new Vector3(1f,0f), new Vector3(5f,0f), 5f).setOnUpdate( (Vector2 val)=>{
+ *  Debug.Log("tweened val:"+val);
+ * } );
+ */ + public static LTDescr value(GameObject gameObject, Vector2 from, Vector2 to, float time) + { + return pushNewTween(gameObject, new Vector3(to.x, to.y, 0), time, options().setValue3().setTo(new Vector3(to.x, to.y, 0f)).setFrom(new Vector3(from.x, from.y, 0))); + } + + /** + * Tween any particular value (Vector3) + * + * @method LeanTween.value (Vector3) + * @param {GameObject} gameObject:GameObject Gameobject that you wish to attach the tween to + * @param {Vector3} from:Vector3 The original value to start the tween from + * @param {Vector3} to:Vector3 The final Vector3 with which to tween to + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Example Javascript:
+ * LeanTween.value( gameObject, new Vector3(1f,0f,0f), new Vector3(5f,0f,0f), 5f).setOnUpdate( function( val:Vector3 ){
+ *  Debug.Log("tweened val:"+val);
+ * } );
+ *
+ * Example C#:
+ * LeanTween.value( gameObject, new Vector3(1f,0f,0f), new Vector3(5f,0f,0f), 5f).setOnUpdate( (Vector3 val)=>{
+ *  Debug.Log("tweened val:"+val);
+ * } );
+ */ + public static LTDescr value(GameObject gameObject, Vector3 from, Vector3 to, float time) + { + return pushNewTween(gameObject, to, time, options().setValue3().setFrom(from)); + } + + /** + * Tween any particular value (Color) + * + * @method LeanTween.value (Color) + * @param {GameObject} gameObject:GameObject Gameobject that you wish to attach the tween to + * @param {Color} from:Color The original value to start the tween from + * @param {Color} to:Color The final Color with which to tween to + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Example Javascript:
+ * LeanTween.value( gameObject, Color.red, Color.yellow, 5f).setOnUpdate( function( val:Color ){
+ *  Debug.Log("tweened val:"+val);
+ * } );
+ *
+ * Example C#:
+ * LeanTween.value( gameObject, Color.red, Color.yellow, 5f).setOnUpdate( (Color val)=>{
+ *  Debug.Log("tweened val:"+val);
+ * } );
+ */ + public static LTDescr value(GameObject gameObject, Color from, Color to, float time) + { + LTDescr lt = pushNewTween(gameObject, new Vector3(1f, to.a, 0f), time, options().setCallbackColor().setPoint(new Vector3(to.r, to.g, to.b)) + .setFromColor(from).setHasInitialized(false)); + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 + SpriteRenderer ren = gameObject.GetComponent(); + lt.spriteRen = ren; +#endif + return lt; + } + + /** + * Tween any particular value, it does not need to be tied to any particular type or GameObject + * + * @method LeanTween.value (float) + * @param {GameObject} GameObject gameObject GameObject with which to tie the tweening with. This is only used when you need to cancel this tween, it does not actually perform any operations on this gameObject + * @param {Action} callOnUpdate:Action The function that is called on every Update frame, this function needs to accept a float value ex: function updateValue( float val ){ } + * @param {float} float from The original value to start the tween from + * @param {float} float to The value to end the tween on + * @param {float} float time The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Example Javascript:
+ * LeanTween.value( gameObject, updateValueExampleCallback, 180f, 270f, 1f).setEase(LeanTweenType.easeOutElastic);
+ * function updateValueExampleCallback( val:float ){
+ *   Debug.Log("tweened value:"+val+" set this to whatever variable you are tweening...");
+ * }
+ *
+ * Example C#:
+ * LeanTween.value( gameObject, updateValueExampleCallback, 180f, 270f, 1f).setEase(LeanTweenType.easeOutElastic);
+ * void updateValueExampleCallback( float val ){
+ *   Debug.Log("tweened value:"+val+" set this to whatever variable you are tweening...");
+ * }
+ */ + + public static LTDescr value(GameObject gameObject, Action callOnUpdate, float from, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setCallback().setTo(new Vector3(to, 0, 0)).setFrom(new Vector3(from, 0, 0)).setOnUpdate(callOnUpdate)); + } + + /** + * Tweens any float value, it does not need to be tied to any particular type or GameObject + * + * @method LeanTween.value (float) + * @param {GameObject} GameObject gameObject GameObject with which to tie the tweening with. This is only used when you need to cancel this tween, it does not actually perform any operations on this gameObject + * @param {Action} callOnUpdateRatio:Action Function that's called every Update frame. It must accept two float values ex: function updateValue( float val, float ratio){ } + * @param {float} float from The original value to start the tween from + * @param {float} float to The value to end the tween on + * @param {float} float time The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Example Javascript:
+ * LeanTween.value( gameObject, updateValueExampleCallback, 180f, 270f, 1f).setEase(LeanTweenType.easeOutElastic);
+ * function updateValueExampleCallback( val:float, ratio:float ){
+ *   Debug.Log("tweened value:"+val+" percent complete:"+ratio*100);
+ * }
+ *
+ * Example C#:
+ * LeanTween.value( gameObject, updateValueExampleCallback, 180f, 270f, 1f).setEase(LeanTweenType.easeOutElastic);
+ * void updateValueExampleCallback( float val, float ratio ){
+ *   Debug.Log("tweened value:"+val+" percent complete:"+ratio*100);
+ * }
+ */ + + public static LTDescr value(GameObject gameObject, Action callOnUpdateRatio, float from, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setCallback().setTo(new Vector3(to, 0, 0)).setFrom(new Vector3(from, 0, 0)).setOnUpdateRatio(callOnUpdateRatio)); + } + + /** + * Tween from one color to another + * + * @method LeanTween.value (Color) + * @param {GameObject} GameObject gameObject GameObject with which to tie the tweening with. This is only used when you need to cancel this tween, it does not actually perform any operations on this gameObject + * @param {Action} callOnUpdate:Action The function that is called on every Update frame, this function needs to accept a color value ex: function updateValue( Color val ){ } + * @param {Color} Color from The original value to start the tween from + * @param {Color} Color to The value to end the tween on + * @param {Color} Color time The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example + * Example Javascript:
+ * LeanTween.value( gameObject, updateValueExampleCallback, Color.red, Color.green, 1f).setEase(LeanTweenType.easeOutElastic);
+ * function updateValueExampleCallback( val:Color ){
+ *   Debug.Log("tweened color:"+val+" set this to whatever variable you are tweening...");
+ * }
+ *
+ * Example C#:
+ * LeanTween.value( gameObject, updateValueExampleCallback, Color.red, Color.green, 1f).setEase(LeanTweenType.easeOutElastic);
+ * void updateValueExampleCallback( Color val ){
+ *   Debug.Log("tweened color:"+val+" set this to whatever variable you are tweening...");
+ * }
+ */ + + public static LTDescr value(GameObject gameObject, Action callOnUpdate, Color from, Color to, float time) + { + return pushNewTween(gameObject, new Vector3(1.0f, to.a, 0.0f), time, options().setCallbackColor().setPoint(new Vector3(to.r, to.g, to.b)) + .setAxis(new Vector3(from.r, from.g, from.b)).setFrom(new Vector3(0.0f, from.a, 0.0f)).setHasInitialized(false).setOnUpdateColor(callOnUpdate)); + } + public static LTDescr value(GameObject gameObject, Action callOnUpdate, Color from, Color to, float time) + { + return pushNewTween(gameObject, new Vector3(1.0f, to.a, 0.0f), time, options().setCallbackColor().setPoint(new Vector3(to.r, to.g, to.b)) + .setAxis(new Vector3(from.r, from.g, from.b)).setFrom(new Vector3(0.0f, from.a, 0.0f)).setHasInitialized(false).setOnUpdateColor(callOnUpdate)); + } + + /** + * Tween any particular value (Vector2), this could be used to tween an arbitrary value like offset property + * + * @method LeanTween.value (Vector2) + * @param {GameObject} gameObject:GameObject Gameobject that you wish to attach the tween to + * @param {Action} callOnUpdate:Action The function that is called on every Update frame, this function needs to accept a float value ex: function updateValue( Vector3 val ){ } + * @param {float} from:Vector2 The original value to start the tween from + * @param {Vector2} to:Vector2 The final Vector3 with which to tween to + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr value(GameObject gameObject, Action callOnUpdate, Vector2 from, Vector2 to, float time) + { + return pushNewTween(gameObject, new Vector3(to.x, to.y, 0f), time, options().setValue3().setTo(new Vector3(to.x, to.y, 0f)).setFrom(new Vector3(from.x, from.y, 0f)).setOnUpdateVector2(callOnUpdate)); + } + + /** + * Tween any particular value (Vector3), this could be used to tween an arbitrary property that uses a Vector + * + * @method LeanTween.value (Vector3) + * @param {GameObject} gameObject:GameObject Gameobject that you wish to attach the tween to + * @param {Action} callOnUpdate:Action The function that is called on every Update frame, this function needs to accept a float value ex: function updateValue( Vector3 val ){ } + * @param {float} from:Vector3 The original value to start the tween from + * @param {Vector3} to:Vector3 The final Vector3 with which to tween to + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr value(GameObject gameObject, Action callOnUpdate, Vector3 from, Vector3 to, float time) + { + return pushNewTween(gameObject, to, time, options().setValue3().setTo(to).setFrom(from).setOnUpdateVector3(callOnUpdate)); + } + + /** + * Tween any particular value (float) + * + * @method LeanTween.value (float,object) + * @param {GameObject} gameObject:GameObject Gameobject that you wish to attach the tween to + * @param {Action} callOnUpdate:Action The function that is called on every Update frame, this function needs to accept a float value ex: function updateValue( Vector3 val, object obj ){ } + * @param {float} from:float The original value to start the tween from + * @param {Vector3} to:float The final Vector3 with which to tween to + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + */ + public static LTDescr value(GameObject gameObject, Action callOnUpdate, float from, float to, float time) + { + return pushNewTween(gameObject, new Vector3(to, 0, 0), time, options().setCallback().setTo(new Vector3(to, 0, 0)).setFrom(new Vector3(from, 0, 0)).setOnUpdate(callOnUpdate, gameObject)); + } + + public static LTDescr delayedSound(AudioClip audio, Vector3 pos, float volume) + { + //Debug.LogError("Delay sound??"); + return pushNewTween(tweenEmpty, pos, 0f, options().setDelayedSound().setTo(pos).setFrom(new Vector3(volume, 0, 0)).setAudio(audio)); + } + + public static LTDescr delayedSound(GameObject gameObject, AudioClip audio, Vector3 pos, float volume) + { + //Debug.LogError("Delay sound??"); + return pushNewTween(gameObject, pos, 0f, options().setDelayedSound().setTo(pos).setFrom(new Vector3(volume, 0, 0)).setAudio(audio)); + } + +#if !UNITY_3_5 && !UNITY_4_0 && !UNITY_4_0_1 && !UNITY_4_1 && !UNITY_4_2 && !UNITY_4_3 && !UNITY_4_5 + + /** + * Move a RectTransform object (used in Unity GUI in 4.6+, for Buttons, Panel, Scrollbar, etc...) + * + * @method LeanTween.move (RectTransform) + * @param {RectTransform} rectTrans:RectTransform RectTransform that you wish to attach the tween to + * @param {Vector3} to:Vector3 The final Vector3 with which to tween to + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.move(gameObject.GetComponent<RectTransform>(), new Vector3(200f,-100f,0f), 1f).setDelay(1f); + */ + public static LTDescr move(RectTransform rectTrans, Vector3 to, float time) + { + return pushNewTween(rectTrans.gameObject, to, time, options().setCanvasMove().setRect(rectTrans)); + } + + /** + * Move a RectTransform object affecting x-axis only (used in Unity GUI in 4.6+, for Buttons, Panel, Scrollbar, etc...) + * + * @method LeanTween.moveX (RectTransform) + * @param {RectTransform} rectTrans:RectTransform RectTransform that you wish to attach the tween to + * @param {float} to:float The final x location with which to tween to + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.moveX(gameObject.GetComponent<RectTransform>(), 200f, 1f).setDelay(1f); + */ + public static LTDescr moveX(RectTransform rectTrans, float to, float time) + { + return pushNewTween(rectTrans.gameObject, new Vector3(to, 0f, 0f), time, options().setCanvasMoveX().setRect(rectTrans)); + } + + /** + * Move a RectTransform object affecting y-axis only (used in Unity GUI in 4.6+, for Buttons, Panel, Scrollbar, etc...) + * + * @method LeanTween.moveY (RectTransform) + * @param {RectTransform} rectTrans:RectTransform RectTransform that you wish to attach the tween to + * @param {float} to:float The final y location with which to tween to + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.moveY(gameObject.GetComponent<RectTransform>(), 200f, 1f).setDelay(1f); + */ + public static LTDescr moveY(RectTransform rectTrans, float to, float time) + { + return pushNewTween(rectTrans.gameObject, new Vector3(to, 0f, 0f), time, options().setCanvasMoveY().setRect(rectTrans)); + } + + /** + * Move a RectTransform object affecting z-axis only (used in Unity GUI in 4.6+, for Buttons, Panel, Scrollbar, etc...)n + * + * @method LeanTween.moveZ (RectTransform) + * @param {RectTransform} rectTrans:RectTransform RectTransform that you wish to attach the tween to + * @param {float} to:float The final x location with which to tween to + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.moveZ(gameObject.GetComponent<RectTransform>(), 200f, 1f).setDelay(1f); + */ + public static LTDescr moveZ(RectTransform rectTrans, float to, float time) + { + return pushNewTween(rectTrans.gameObject, new Vector3(to, 0f, 0f), time, options().setCanvasMoveZ().setRect(rectTrans)); + } + + /** + * Rotate a RectTransform object (used in Unity GUI in 4.6+, for Buttons, Panel, Scrollbar, etc...) + * + * @method LeanTween.rotate (RectTransform) + * @param {RectTransform} rectTrans:RectTransform RectTransform that you wish to attach the tween to + * @param {float} to:float The degree with which to rotate the RectTransform + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.rotate(gameObject.GetComponent<RectTransform>(), 90f, 1f).setDelay(1f); + */ + public static LTDescr rotate(RectTransform rectTrans, float to, float time) + { + return pushNewTween(rectTrans.gameObject, new Vector3(to, 0f, 0f), time, options().setCanvasRotateAround().setRect(rectTrans).setAxis(Vector3.forward)); + } + + public static LTDescr rotate(RectTransform rectTrans, Vector3 to, float time) + { + return pushNewTween(rectTrans.gameObject, to, time, options().setCanvasRotateAround().setRect(rectTrans).setAxis(Vector3.forward)); + } + + /** + * Rotate a RectTransform object (used in Unity GUI in 4.6+, for Buttons, Panel, Scrollbar, etc...) + * + * @method LeanTween.rotateAround (RectTransform) + * @param {RectTransform} rectTrans:RectTransform RectTransform that you wish to attach the tween to + * @param {Vector3} axis:Vector3 The axis in which to rotate the RectTransform (Vector3.forward is most commonly used) + * @param {float} to:float The degree with which to rotate the RectTransform + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.rotateAround(gameObject.GetComponent<RectTransform>(), Vector3.forward, 90f, 1f).setDelay(1f); + */ + public static LTDescr rotateAround(RectTransform rectTrans, Vector3 axis, float to, float time) + { + return pushNewTween(rectTrans.gameObject, new Vector3(to, 0f, 0f), time, options().setCanvasRotateAround().setRect(rectTrans).setAxis(axis)); + } + + /** + * Rotate a RectTransform object around it's local axis (used in Unity GUI in 4.6+, for Buttons, Panel, Scrollbar, etc...) + * + * @method LeanTween.rotateAroundLocal (RectTransform) + * @param {RectTransform} rectTrans:RectTransform RectTransform that you wish to attach the tween to + * @param {Vector3} axis:Vector3 The local axis in which to rotate the RectTransform (Vector3.forward is most commonly used) + * @param {float} to:float The degree with which to rotate the RectTransform + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.rotateAroundLocal(gameObject.GetComponent<RectTransform>(), Vector3.forward, 90f, 1f).setDelay(1f); + */ + public static LTDescr rotateAroundLocal(RectTransform rectTrans, Vector3 axis, float to, float time) + { + return pushNewTween(rectTrans.gameObject, new Vector3(to, 0f, 0f), time, options().setCanvasRotateAroundLocal().setRect(rectTrans).setAxis(axis)); + } + + /** + * Scale a RectTransform object (used in Unity GUI in 4.6+, for Buttons, Panel, Scrollbar, etc...) + * + * @method LeanTween.scale (RectTransform) + * @param {RectTransform} rectTrans:RectTransform RectTransform that you wish to attach the tween to + * @param {Vector3} to:Vector3 The final Vector3 with which to tween to (localScale) + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.scale(gameObject.GetComponent<RectTransform>(), gameObject.GetComponent<RectTransform>().localScale*2f, 1f).setDelay(1f); + */ + public static LTDescr scale(RectTransform rectTrans, Vector3 to, float time) + { + return pushNewTween(rectTrans.gameObject, to, time, options().setCanvasScale().setRect(rectTrans)); + } + + /** + * Change the sizeDelta of a RectTransform object (used in Unity Canvas, for Buttons, Panel, Scrollbar, etc...) + * + * @method LeanTween.size (RectTransform) + * @param {RectTransform} rectTrans:RectTransform RectTransform that you wish to attach the tween to + * @param {Vector2} to:Vector2 The final Vector2 the tween will end at for sizeDelta property + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.size(gameObject.GetComponent<RectTransform>(), gameObject.GetComponent<RectTransform>().sizeDelta*2f, 1f).setDelay(1f); + */ + public static LTDescr size(RectTransform rectTrans, Vector2 to, float time) + { + return pushNewTween(rectTrans.gameObject, to, time, options().setCanvasSizeDelta().setRect(rectTrans)); + } + + /** + * Alpha an Image Component attached to a RectTransform (used in Unity GUI in 4.6+, for Buttons, Panel, Scrollbar, etc...) + * + * @method LeanTween.alpha (RectTransform) + * @param {RectTransform} rectTrans:RectTransform RectTransform that you wish to attach the tween to + * @param {float} to:float The final Vector3 with which to tween to (localScale) + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.alpha(gameObject.GetComponent<RectTransform>(), 0.5f, 1f).setDelay(1f); + */ + public static LTDescr alpha(RectTransform rectTrans, float to, float time) + { + return pushNewTween(rectTrans.gameObject, new Vector3(to, 0f, 0f), time, options().setCanvasAlpha().setRect(rectTrans)); + } + + /** + * Change the Color of an Image Component attached to a RectTransform (used in Unity GUI in 4.6+, for Buttons, Panel, Scrollbar, etc...) + * + * @method LeanTween.alpha (RectTransform) + * @param {RectTransform} rectTrans:RectTransform RectTransform that you wish to attach the tween to + * @param {float} to:float The final Vector3 with which to tween to (localScale) + * @param {float} time:float The time to complete the tween in + * @return {LTDescr} LTDescr an object that distinguishes the tween + * @example LeanTween.color(gameObject.GetComponent<RectTransform>(), 0.5f, 1f).setDelay(1f); + */ + public static LTDescr color(RectTransform rectTrans, Color to, float time) + { + return pushNewTween(rectTrans.gameObject, new Vector3(1.0f, to.a, 0.0f), time, options().setCanvasColor().setRect(rectTrans).setPoint(new Vector3(to.r, to.g, to.b))); + } + +#endif + + // Tweening Functions - Thanks to Robert Penner and GFX47 + + public static float tweenOnCurve(LTDescr tweenDescr, float ratioPassed) + { + // Debug.Log("single ratio:"+ratioPassed+" tweenDescr.animationCurve.Evaluate(ratioPassed):"+tweenDescr.animationCurve.Evaluate(ratioPassed)); + return tweenDescr.from.x + (tweenDescr.diff.x) * tweenDescr.optional.animationCurve.Evaluate(ratioPassed); + } + + public static Vector3 tweenOnCurveVector(LTDescr tweenDescr, float ratioPassed) + { + return new Vector3(tweenDescr.from.x + (tweenDescr.diff.x) * tweenDescr.optional.animationCurve.Evaluate(ratioPassed), + tweenDescr.from.y + (tweenDescr.diff.y) * tweenDescr.optional.animationCurve.Evaluate(ratioPassed), + tweenDescr.from.z + (tweenDescr.diff.z) * tweenDescr.optional.animationCurve.Evaluate(ratioPassed)); + } + + public static float easeOutQuadOpt(float start, float diff, float ratioPassed) + { + return -diff * ratioPassed * (ratioPassed - 2) + start; + } + + public static float easeInQuadOpt(float start, float diff, float ratioPassed) + { + return diff * ratioPassed * ratioPassed + start; + } + + public static float easeInOutQuadOpt(float start, float diff, float ratioPassed) + { + ratioPassed /= .5f; + if (ratioPassed < 1) return diff / 2 * ratioPassed * ratioPassed + start; + ratioPassed--; + return -diff / 2 * (ratioPassed * (ratioPassed - 2) - 1) + start; + } + + public static Vector3 easeInOutQuadOpt(Vector3 start, Vector3 diff, float ratioPassed) + { + ratioPassed /= .5f; + if (ratioPassed < 1) return diff / 2 * ratioPassed * ratioPassed + start; + ratioPassed--; + return -diff / 2 * (ratioPassed * (ratioPassed - 2) - 1) + start; + } + + public static float linear(float start, float end, float val) + { + return Mathf.Lerp(start, end, val); + } + + public static float clerp(float start, float end, float val) + { + float min = 0.0f; + float max = 360.0f; + float half = Mathf.Abs((max - min) / 2.0f); + float retval = 0.0f; + float diff = 0.0f; + if ((end - start) < -half) + { + diff = ((max - start) + end) * val; + retval = start + diff; + } + else if ((end - start) > half) + { + diff = -((max - end) + start) * val; + retval = start + diff; + } + else retval = start + (end - start) * val; + return retval; + } + + public static float spring(float start, float end, float val) + { + val = Mathf.Clamp01(val); + val = (Mathf.Sin(val * Mathf.PI * (0.2f + 2.5f * val * val * val)) * Mathf.Pow(1f - val, 2.2f) + val) * (1f + (1.2f * (1f - val))); + return start + (end - start) * val; + } + + public static float easeInQuad(float start, float end, float val) + { + end -= start; + return end * val * val + start; + } + + public static float easeOutQuad(float start, float end, float val) + { + end -= start; + return -end * val * (val - 2) + start; + } + + public static float easeInOutQuad(float start, float end, float val) + { + val /= .5f; + end -= start; + if (val < 1) return end / 2 * val * val + start; + val--; + return -end / 2 * (val * (val - 2) - 1) + start; + } + + + public static float easeInOutQuadOpt2(float start, float diffBy2, float val, float val2) + { + val /= .5f; + if (val < 1) return diffBy2 * val2 + start; + val--; + return -diffBy2 * ((val2 - 2) - 1f) + start; + } + + public static float easeInCubic(float start, float end, float val) + { + end -= start; + return end * val * val * val + start; + } + + public static float easeOutCubic(float start, float end, float val) + { + val--; + end -= start; + return end * (val * val * val + 1) + start; + } + + public static float easeInOutCubic(float start, float end, float val) + { + val /= .5f; + end -= start; + if (val < 1) return end / 2 * val * val * val + start; + val -= 2; + return end / 2 * (val * val * val + 2) + start; + } + + public static float easeInQuart(float start, float end, float val) + { + end -= start; + return end * val * val * val * val + start; + } + + public static float easeOutQuart(float start, float end, float val) + { + val--; + end -= start; + return -end * (val * val * val * val - 1) + start; + } + + public static float easeInOutQuart(float start, float end, float val) + { + val /= .5f; + end -= start; + if (val < 1) return end / 2 * val * val * val * val + start; + val -= 2; + return -end / 2 * (val * val * val * val - 2) + start; + } + + public static float easeInQuint(float start, float end, float val) + { + end -= start; + return end * val * val * val * val * val + start; + } + + public static float easeOutQuint(float start, float end, float val) + { + val--; + end -= start; + return end * (val * val * val * val * val + 1) + start; + } + + public static float easeInOutQuint(float start, float end, float val) + { + val /= .5f; + end -= start; + if (val < 1) return end / 2 * val * val * val * val * val + start; + val -= 2; + return end / 2 * (val * val * val * val * val + 2) + start; + } + + public static float easeInSine(float start, float end, float val) + { + end -= start; + return -end * Mathf.Cos(val / 1 * (Mathf.PI / 2)) + end + start; + } + + public static float easeOutSine(float start, float end, float val) + { + end -= start; + return end * Mathf.Sin(val / 1 * (Mathf.PI / 2)) + start; + } + + public static float easeInOutSine(float start, float end, float val) + { + end -= start; + return -end / 2 * (Mathf.Cos(Mathf.PI * val / 1) - 1) + start; + } + + public static float easeInExpo(float start, float end, float val) + { + end -= start; + return end * Mathf.Pow(2, 10 * (val / 1 - 1)) + start; + } + + public static float easeOutExpo(float start, float end, float val) + { + end -= start; + return end * (-Mathf.Pow(2, -10 * val / 1) + 1) + start; + } + + public static float easeInOutExpo(float start, float end, float val) + { + val /= .5f; + end -= start; + if (val < 1) return end / 2 * Mathf.Pow(2, 10 * (val - 1)) + start; + val--; + return end / 2 * (-Mathf.Pow(2, -10 * val) + 2) + start; + } + + public static float easeInCirc(float start, float end, float val) + { + end -= start; + return -end * (Mathf.Sqrt(1 - val * val) - 1) + start; + } + + public static float easeOutCirc(float start, float end, float val) + { + val--; + end -= start; + return end * Mathf.Sqrt(1 - val * val) + start; + } + + public static float easeInOutCirc(float start, float end, float val) + { + val /= .5f; + end -= start; + if (val < 1) return -end / 2 * (Mathf.Sqrt(1 - val * val) - 1) + start; + val -= 2; + return end / 2 * (Mathf.Sqrt(1 - val * val) + 1) + start; + } + + public static float easeInBounce(float start, float end, float val) + { + end -= start; + float d = 1f; + return end - easeOutBounce(0, end, d - val) + start; + } + + public static float easeOutBounce(float start, float end, float val) + { + val /= 1f; + end -= start; + if (val < (1 / 2.75f)) + { + return end * (7.5625f * val * val) + start; + } + else if (val < (2 / 2.75f)) + { + val -= (1.5f / 2.75f); + return end * (7.5625f * (val) * val + .75f) + start; + } + else if (val < (2.5 / 2.75)) + { + val -= (2.25f / 2.75f); + return end * (7.5625f * (val) * val + .9375f) + start; + } + else + { + val -= (2.625f / 2.75f); + return end * (7.5625f * (val) * val + .984375f) + start; + } + } + + public static float easeInOutBounce(float start, float end, float val) + { + end -= start; + float d = 1f; + if (val < d / 2) return easeInBounce(0, end, val * 2) * 0.5f + start; + else return easeOutBounce(0, end, val * 2 - d) * 0.5f + end * 0.5f + start; + } + + public static float easeInBack(float start, float end, float val, float overshoot = 1.0f) + { + end -= start; + val /= 1; + float s = 1.70158f * overshoot; + return end * (val) * val * ((s + 1) * val - s) + start; + } + + public static float easeOutBack(float start, float end, float val, float overshoot = 1.0f) + { + float s = 1.70158f * overshoot; + end -= start; + val = (val / 1) - 1; + return end * ((val) * val * ((s + 1) * val + s) + 1) + start; + } + + public static float easeInOutBack(float start, float end, float val, float overshoot = 1.0f) + { + float s = 1.70158f * overshoot; + end -= start; + val /= .5f; + if ((val) < 1) + { + s *= (1.525f) * overshoot; + return end / 2 * (val * val * (((s) + 1) * val - s)) + start; + } + val -= 2; + s *= (1.525f) * overshoot; + return end / 2 * ((val) * val * (((s) + 1) * val + s) + 2) + start; + } + + public static float easeInElastic(float start, float end, float val, float overshoot = 1.0f, float period = 0.3f) + { + end -= start; + + float p = period; + float s = 0f; + float a = 0f; + + if (val == 0f) return start; + + if (val == 1f) return start + end; + + if (a == 0f || a < Mathf.Abs(end)) + { + a = end; + s = p / 4f; + } + else + { + s = p / (2f * Mathf.PI) * Mathf.Asin(end / a); + } + + if (overshoot > 1f && val > 0.6f) + overshoot = 1f + ((1f - val) / 0.4f * (overshoot - 1f)); + // Debug.Log("ease in elastic val:"+val+" a:"+a+" overshoot:"+overshoot); + + val = val - 1f; + return start - (a * Mathf.Pow(2f, 10f * val) * Mathf.Sin((val - s) * (2f * Mathf.PI) / p)) * overshoot; + } + + public static float easeOutElastic(float start, float end, float val, float overshoot = 1.0f, float period = 0.3f) + { + end -= start; + + float p = period; + float s = 0f; + float a = 0f; + + if (val == 0f) return start; + + // Debug.Log("ease out elastic val:"+val+" a:"+a); + if (val == 1f) return start + end; + + if (a == 0f || a < Mathf.Abs(end)) + { + a = end; + s = p / 4f; + } + else + { + s = p / (2f * Mathf.PI) * Mathf.Asin(end / a); + } + if (overshoot > 1f && val < 0.4f) + overshoot = 1f + (val / 0.4f * (overshoot - 1f)); + // Debug.Log("ease out elastic val:"+val+" a:"+a+" overshoot:"+overshoot); + + return start + end + a * Mathf.Pow(2f, -10f * val) * Mathf.Sin((val - s) * (2f * Mathf.PI) / p) * overshoot; + } + + public static float easeInOutElastic(float start, float end, float val, float overshoot = 1.0f, float period = 0.3f) + { + end -= start; + + float p = period; + float s = 0f; + float a = 0f; + + if (val == 0f) return start; + + val = val / (1f / 2f); + if (val == 2f) return start + end; + + if (a == 0f || a < Mathf.Abs(end)) + { + a = end; + s = p / 4f; + } + else + { + s = p / (2f * Mathf.PI) * Mathf.Asin(end / a); + } + + if (overshoot > 1f) + { + if (val < 0.2f) + { + overshoot = 1f + (val / 0.2f * (overshoot - 1f)); + } + else if (val > 0.8f) + { + overshoot = 1f + ((1f - val) / 0.2f * (overshoot - 1f)); + } + } + + if (val < 1f) + { + val = val - 1f; + return start - 0.5f * (a * Mathf.Pow(2f, 10f * val) * Mathf.Sin((val - s) * (2f * Mathf.PI) / p)) * overshoot; + } + val = val - 1f; + return end + start + a * Mathf.Pow(2f, -10f * val) * Mathf.Sin((val - s) * (2f * Mathf.PI) / p) * 0.5f * overshoot; + } + + // Mark: LeanTween Following + + /** + * Follow another transforms position/scale/color with a damp transition (eases in and out to destination with no overshoot) + * + * @method LeanTween.followDamp + * @param {Transform} transform:Transform the transform you wish to be the follower + * @param {Transform} transform:Transform the transform you wish to follow + * @param {LeanProp} leanProp:LeanProp enum of the type of following you wish to do position, scale, color, etc. + * @param {float} smoothTime:float roughly the time it takes to reach the destination + * @param {float} [maxSpeed]:float maximum speed at which it moves towards the destination + * @example + * LeanTween.followDamp(transform, followTransform, LeanProp.localY, 1.1f); + */ + public static LTDescr followDamp(Transform trans, Transform target, LeanProp prop, float smoothTime, float maxSpeed = -1f) + { + var d = pushNewTween(trans.gameObject, Vector3.zero, float.MaxValue, options().setFollow().setTarget(target)); + + switch (prop) + { + case LeanProp.localPosition: + d.optional.axis = d.trans.localPosition; + d.easeInternal = () => + { + d.optional.axis = LeanSmooth.damp(d.optional.axis, d.toTrans.localPosition, ref d.fromInternal, smoothTime, maxSpeed, Time.deltaTime); + d.trans.localPosition = d.optional.axis + d.toInternal; + }; break; + case LeanProp.position: + d.diff = d.trans.position; + d.easeInternal = () => + { + d.optional.axis = LeanSmooth.damp(d.optional.axis, d.toTrans.position, ref d.fromInternal, smoothTime, maxSpeed, Time.deltaTime); + d.trans.position = d.optional.axis + d.toInternal; + }; break; + case LeanProp.localX: + d.easeInternal = () => + { + d.trans.LeanSetLocalPosX(LeanSmooth.damp(d.trans.localPosition.x, d.toTrans.localPosition.x, ref d.fromInternal.x, smoothTime, maxSpeed, Time.deltaTime)); + }; break; + case LeanProp.localY: + d.easeInternal = () => + { + d.trans.LeanSetLocalPosY(LeanSmooth.damp(d.trans.localPosition.y, d.toTrans.localPosition.y, ref d.fromInternal.y, smoothTime, maxSpeed, Time.deltaTime)); + }; break; + case LeanProp.localZ: + d.easeInternal = () => + { + d.trans.LeanSetLocalPosZ(LeanSmooth.damp(d.trans.localPosition.z, d.toTrans.localPosition.z, ref d.fromInternal.z, smoothTime, maxSpeed, Time.deltaTime)); + }; break; + case LeanProp.x: + d.easeInternal = () => + { + d.trans.LeanSetPosX(LeanSmooth.damp(d.trans.position.x, d.toTrans.position.x, ref d.fromInternal.x, smoothTime, maxSpeed, Time.deltaTime)); + }; break; + case LeanProp.y: + d.easeInternal = () => + { + d.trans.LeanSetPosY(LeanSmooth.damp(d.trans.position.y, d.toTrans.position.y, ref d.fromInternal.y, smoothTime, maxSpeed, Time.deltaTime)); + }; break; + case LeanProp.z: + d.easeInternal = () => + { + d.trans.LeanSetPosZ(LeanSmooth.damp(d.trans.position.z, d.toTrans.position.z, ref d.fromInternal.z, smoothTime, maxSpeed, Time.deltaTime)); + }; break; + case LeanProp.scale: + d.easeInternal = () => + { + d.trans.localScale = LeanSmooth.damp(d.trans.localScale, d.toTrans.localScale, ref d.fromInternal, smoothTime, maxSpeed, Time.deltaTime); + }; break; + case LeanProp.color: + d.easeInternal = () => + { + var col = LeanSmooth.damp(d.trans.LeanColor(), d.toTrans.LeanColor(), ref d.optional.color, smoothTime, maxSpeed, Time.deltaTime); + d.trans.GetComponent().material.color = col; + }; break; + } + + return d; + } + + /** + * Follow another transforms position/scale/color with a springy transition (eases in and out to destination with possible overshoot bounciness) + * + * @method LeanTween.followSpring + * @param {Transform} transform:Transform the transform you wish to be the follower + * @param {Transform} transform:Transform the transform you wish to follow + * @param {LeanProp} leanProp:LeanProp enum of the type of following you wish to do position, scale, color, etc. + * @param {float} smoothTime:float roughly the time it takes to reach the destination + * @param {float} [maxSpeed]:float maximum speed at which it moves towards the destination + * @param {float} [friction]:float rate at which the spring is slowed down once it reaches it's destination + * @param {float} [accelRate]:float the rate it accelerates from it's initial position + * @example + * LeanTween.followSpring(transform, followTransform, LeanProp.localY); + */ + public static LTDescr followSpring(Transform trans, Transform target, LeanProp prop, float smoothTime, float maxSpeed = -1f, float friction = 2f, float accelRate = 0.5f) + { + var d = pushNewTween(trans.gameObject, Vector3.zero, float.MaxValue, options().setFollow().setTarget(target)); + switch (prop) + { + case LeanProp.localPosition: + d.optional.axis = d.trans.localPosition; + d.easeInternal = () => + { + d.optional.axis = LeanSmooth.spring(d.optional.axis, d.toTrans.localPosition, ref d.fromInternal, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate); + d.trans.localPosition = d.optional.axis + d.toInternal; + }; break; + case LeanProp.position: + d.diff = d.trans.position; + d.easeInternal = () => + { + d.diff = LeanSmooth.spring(d.diff, d.toTrans.position, ref d.fromInternal, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate); + d.trans.position = d.diff;// + d.toInternal; + }; break; + case LeanProp.localX: + d.easeInternal = () => + { + d.trans.LeanSetLocalPosX(LeanSmooth.spring(d.trans.localPosition.x, d.toTrans.localPosition.x, ref d.fromInternal.x, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate)); + }; break; + case LeanProp.localY: + d.easeInternal = () => + { + d.trans.LeanSetLocalPosY(LeanSmooth.spring(d.trans.localPosition.y, d.toTrans.localPosition.y, ref d.fromInternal.y, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate)); + }; break; + case LeanProp.localZ: + d.easeInternal = () => + { + d.trans.LeanSetLocalPosZ(LeanSmooth.spring(d.trans.localPosition.z, d.toTrans.localPosition.z, ref d.fromInternal.z, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate)); + }; break; + case LeanProp.x: + d.easeInternal = () => + { + d.trans.LeanSetPosX(LeanSmooth.spring(d.trans.position.x, d.toTrans.position.x, ref d.fromInternal.x, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate)); + }; break; + case LeanProp.y: + d.easeInternal = () => + { + d.trans.LeanSetPosY(LeanSmooth.spring(d.trans.position.y, d.toTrans.position.y, ref d.fromInternal.y, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate)); + }; break; + case LeanProp.z: + d.easeInternal = () => + { + d.trans.LeanSetPosZ(LeanSmooth.spring(d.trans.position.z, d.toTrans.position.z, ref d.fromInternal.z, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate)); + }; break; + case LeanProp.scale: + d.easeInternal = () => + { + d.trans.localScale = LeanSmooth.spring(d.trans.localScale, d.toTrans.localScale, ref d.fromInternal, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate); + }; break; + case LeanProp.color: + d.easeInternal = () => + { + var col = LeanSmooth.spring(d.trans.LeanColor(), d.toTrans.LeanColor(), ref d.optional.color, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate); + d.trans.GetComponent().material.color = col; + }; break; + } + + return d; + } + + /** + * Follow another transforms position/scale/color (with an ease that bounces back some when it reaches it's destination) + * + * @method LeanTween.followBounceOut + * @param {Transform} transform:Transform the transform you wish to be the follower + * @param {Transform} transform:Transform the transform you wish to follow + * @param {LeanProp} leanProp:LeanProp enum of the type of following you wish to do position, scale, color, etc. + * @param {float} smoothTime:float roughly the time it takes to reach the destination + * @param {float} [maxSpeed]:float maximum speed at which it moves towards the destination + * @param {float} [friction]:float rate at which the spring is slowed down once it reaches it's destination + * @param {float} [accelRate]:float the rate it accelerates from it's initial position + * @param {float} [hitDamp]:float the rate at which to dampen the bounciness of when it reaches it's destination + * @example + * LeanTween.followBounceOut(transform, followTransform, LeanProp.localY, 1.1f); + */ + public static LTDescr followBounceOut(Transform trans, Transform target, LeanProp prop, float smoothTime, float maxSpeed = -1f, float friction = 2f, float accelRate = 0.5f, float hitDamping = 0.9f) + { + var d = pushNewTween(trans.gameObject, Vector3.zero, float.MaxValue, options().setFollow().setTarget(target)); + switch (prop) + { + case LeanProp.localPosition: + d.optional.axis = d.trans.localPosition; + d.easeInternal = () => + { + d.optional.axis = LeanSmooth.bounceOut(d.optional.axis, d.toTrans.localPosition, ref d.fromInternal, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate, hitDamping); + d.trans.localPosition = d.optional.axis + d.toInternal; + }; break; + case LeanProp.position: + d.easeInternal = () => + { + d.optional.axis = LeanSmooth.bounceOut(d.optional.axis, d.toTrans.position, ref d.fromInternal, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate, hitDamping); + d.trans.position = d.optional.axis + d.toInternal; + }; break; + case LeanProp.localX: + d.easeInternal = () => + { + d.trans.LeanSetLocalPosX(LeanSmooth.bounceOut(d.trans.localPosition.x, d.toTrans.localPosition.x, ref d.fromInternal.x, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate, hitDamping)); + }; break; + case LeanProp.localY: + d.easeInternal = () => + { + d.trans.LeanSetLocalPosY(LeanSmooth.bounceOut(d.trans.localPosition.y, d.toTrans.localPosition.y, ref d.fromInternal.y, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate, hitDamping)); + }; break; + case LeanProp.localZ: + d.easeInternal = () => + { + d.trans.LeanSetLocalPosZ(LeanSmooth.bounceOut(d.trans.localPosition.z, d.toTrans.localPosition.z, ref d.fromInternal.z, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate, hitDamping)); + }; break; + case LeanProp.x: + d.easeInternal = () => + { + d.trans.LeanSetPosX(LeanSmooth.bounceOut(d.trans.position.x, d.toTrans.position.x, ref d.fromInternal.x, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate, hitDamping)); + }; break; + case LeanProp.y: + d.easeInternal = () => + { + d.trans.LeanSetPosY(LeanSmooth.bounceOut(d.trans.position.y, d.toTrans.position.y, ref d.fromInternal.y, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate, hitDamping)); + }; break; + case LeanProp.z: + d.easeInternal = () => + { + d.trans.LeanSetPosZ(LeanSmooth.bounceOut(d.trans.position.z, d.toTrans.position.z, ref d.fromInternal.z, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate, hitDamping)); + }; break; + case LeanProp.scale: + d.easeInternal = () => + { + d.trans.localScale = LeanSmooth.bounceOut(d.trans.localScale, d.toTrans.localScale, ref d.fromInternal, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate, hitDamping); + }; break; + case LeanProp.color: + d.easeInternal = () => + { + var col = LeanSmooth.bounceOut(d.trans.LeanColor(), d.toTrans.LeanColor(), ref d.optional.color, smoothTime, maxSpeed, Time.deltaTime, friction, accelRate, hitDamping); + d.trans.GetComponent().material.color = col; + }; break; + } + + return d; + } + + /** + * Follow another transforms position/scale/color with a constant speed + * + * @method LeanTween.followLinear + * @param {Transform} transform:Transform the transform you wish to be the follower + * @param {Transform} transform:Transform the transform you wish to follow + * @param {LeanProp} leanProp:LeanProp enum of the type of following you wish to do position, scale, color, etc. + * @param {float} moveSpeed:float roughly the time it takes to reach the destination + * @example + * LeanTween.followLinear(transform, followTransform, LeanProp.localY, 50f); + */ + public static LTDescr followLinear(Transform trans, Transform target, LeanProp prop, float moveSpeed) + { + var d = pushNewTween(trans.gameObject, Vector3.zero, float.MaxValue, options().setFollow().setTarget(target)); + switch (prop) + { + case LeanProp.localPosition: + d.optional.axis = d.trans.localPosition; + d.easeInternal = () => + { + d.optional.axis = LeanSmooth.linear(d.optional.axis, d.toTrans.localPosition, moveSpeed); + d.trans.localPosition = d.optional.axis + d.toInternal; + }; break; + case LeanProp.position: + d.easeInternal = () => + { + d.trans.position = LeanSmooth.linear(d.trans.position, d.toTrans.position, moveSpeed); + }; break; + case LeanProp.localX: + d.easeInternal = () => + { + d.trans.LeanSetLocalPosX(LeanSmooth.linear(d.trans.localPosition.x, d.toTrans.localPosition.x, moveSpeed)); + }; break; + case LeanProp.localY: + d.easeInternal = () => + { + d.trans.LeanSetLocalPosY(LeanSmooth.linear(d.trans.localPosition.y, d.toTrans.localPosition.y, moveSpeed)); + }; break; + case LeanProp.localZ: + d.easeInternal = () => + { + d.trans.LeanSetLocalPosZ(LeanSmooth.linear(d.trans.localPosition.z, d.toTrans.localPosition.z, moveSpeed)); + }; break; + case LeanProp.x: + d.easeInternal = () => + { + d.trans.LeanSetPosX(LeanSmooth.linear(d.trans.position.x, d.toTrans.position.x, moveSpeed)); + }; break; + case LeanProp.y: + d.easeInternal = () => + { + d.trans.LeanSetPosY(LeanSmooth.linear(d.trans.position.y, d.toTrans.position.y, moveSpeed)); + }; break; + case LeanProp.z: + d.easeInternal = () => + { + d.trans.LeanSetPosZ(LeanSmooth.linear(d.trans.position.z, d.toTrans.position.z, moveSpeed)); + }; break; + case LeanProp.scale: + d.easeInternal = () => + { + d.trans.localScale = LeanSmooth.linear(d.trans.localScale, d.toTrans.localScale, moveSpeed); + }; break; + case LeanProp.color: + d.easeInternal = () => + { + var col = LeanSmooth.linear(d.trans.LeanColor(), d.toTrans.LeanColor(), moveSpeed); + d.trans.GetComponent().material.color = col; + }; break; + } + + return d; + } + + // LeanTween Listening/Dispatch + + private static System.Action[] eventListeners; + private static GameObject[] goListeners; + private static int eventsMaxSearch = 0; + public static int EVENTS_MAX = 10; + public static int LISTENERS_MAX = 10; + private static int INIT_LISTENERS_MAX = LISTENERS_MAX; + + public static void addListener(int eventId, System.Action callback) + { + addListener(tweenEmpty, eventId, callback); + } + + /** + * Add a listener method to be called when the appropriate LeanTween.dispatchEvent is called + * + * @method LeanTween.addListener + * @param {GameObject} caller:GameObject the gameObject the listener is attached to + * @param {int} eventId:int a unique int that describes the event (best to use an enum) + * @param {System.Action} callback:System.Action the method to call when the event has been dispatched + * @example + * LeanTween.addListener(gameObject, (int)MyEvents.JUMP, jumpUp);
+ *
+ * void jumpUp( LTEvent e ){ Debug.Log("jump!"); }
+ */ + public static void addListener(GameObject caller, int eventId, System.Action callback) + { + if (eventListeners == null) + { + INIT_LISTENERS_MAX = LISTENERS_MAX; + eventListeners = new System.Action[EVENTS_MAX * LISTENERS_MAX]; + goListeners = new GameObject[EVENTS_MAX * LISTENERS_MAX]; + } + // Debug.Log("searching for an empty space for:"+caller + " eventid:"+event); + for (i = 0; i < INIT_LISTENERS_MAX; i++) + { + int point = eventId * INIT_LISTENERS_MAX + i; + if (goListeners[point] == null || eventListeners[point] == null) + { + eventListeners[point] = callback; + goListeners[point] = caller; + if (i >= eventsMaxSearch) + eventsMaxSearch = i + 1; + // Debug.Log("adding event for:"+caller.name); + + return; + } +#if UNITY_FLASH + if(goListeners[ point ] == caller && System.Object.ReferenceEquals( eventListeners[ point ], callback)){ + // Debug.Log("This event is already being listened for."); + return; + } +#else + if (goListeners[point] == caller && System.Object.Equals(eventListeners[point], callback)) + { + // Debug.Log("This event is already being listened for."); + return; + } +#endif + } + Debug.LogError("You ran out of areas to add listeners, consider increasing LISTENERS_MAX, ex: LeanTween.LISTENERS_MAX = " + (LISTENERS_MAX * 2)); + } + + public static bool removeListener(int eventId, System.Action callback) + { + return removeListener(tweenEmpty, eventId, callback); + } + + public static bool removeListener(int eventId) + { + int point = eventId * INIT_LISTENERS_MAX + i; + eventListeners[point] = null; + goListeners[point] = null; + return true; + } + + + /** + * Remove an event listener you have added + * @method LeanTween.removeListener + * @param {GameObject} caller:GameObject the gameObject the listener is attached to + * @param {int} eventId:int a unique int that describes the event (best to use an enum) + * @param {System.Action} callback:System.Action the method that was specified to call when the event has been dispatched + * @example + * LeanTween.removeListener(gameObject, (int)MyEvents.JUMP, jumpUp);
+ *
+ * void jumpUp( LTEvent e ){ }
+ */ + public static bool removeListener(GameObject caller, int eventId, System.Action callback) + { + for (i = 0; i < eventsMaxSearch; i++) + { + int point = eventId * INIT_LISTENERS_MAX + i; +#if UNITY_FLASH + if(goListeners[ point ] == caller && System.Object.ReferenceEquals( eventListeners[ point ], callback) ){ +#else + if (goListeners[point] == caller && System.Object.Equals(eventListeners[point], callback)) + { +#endif + eventListeners[point] = null; + goListeners[point] = null; + return true; + } + } + return false; + } + + /** + * Tell the added listeners that you are dispatching the event + * @method LeanTween.dispatchEvent + * @param {int} eventId:int a unique int that describes the event (best to use an enum) + * @example + * LeanTween.dispatchEvent( (int)MyEvents.JUMP );
+ */ + public static void dispatchEvent(int eventId) + { + dispatchEvent(eventId, null); + } + + /** + * Tell the added listeners that you are dispatching the event + * @method LeanTween.dispatchEvent + * @param {int} eventId:int a unique int that describes the event (best to use an enum) + * @param {object} data:object Pass data to the listener, access it from the listener with *.data on the LTEvent object + * @example + * LeanTween.dispatchEvent( (int)MyEvents.JUMP, transform );
+ *
+ * void jumpUp( LTEvent e ){
+ *   Transform tran = (Transform)e.data;
+ * }
+ */ + public static void dispatchEvent(int eventId, object data) + { + for (int k = 0; k < eventsMaxSearch; k++) + { + int point = eventId * INIT_LISTENERS_MAX + k; + if (eventListeners[point] != null) + { + if (goListeners[point]) + { + eventListeners[point](new LTEvent(eventId, data)); + } + else + { + eventListeners[point] = null; + } + } + } + } + + +} // End LeanTween class + +public class LTUtility +{ + + public static Vector3[] reverse(Vector3[] arr) + { + int length = arr.Length; + int left = 0; + int right = length - 1; + + for (; left < right; left += 1, right -= 1) + { + Vector3 temporary = arr[left]; + arr[left] = arr[right]; + arr[right] = temporary; + } + return arr; + } +} + +public class LTBezier +{ + public float length; + + private Vector3 a; + private Vector3 aa; + private Vector3 bb; + private Vector3 cc; + private float len; + private float[] arcLengths; + + public LTBezier(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float precision) + { + this.a = a; + aa = (-a + 3 * (b - c) + d); + bb = 3 * (a + c) - 6 * b; + cc = 3 * (b - a); + + this.len = 1.0f / precision; + arcLengths = new float[(int)this.len + (int)1]; + arcLengths[0] = 0; + + Vector3 ov = a; + Vector3 v; + float clen = 0.0f; + for (int i = 1; i <= this.len; i++) + { + v = bezierPoint(i * precision); + clen += (ov - v).magnitude; + this.arcLengths[i] = clen; + ov = v; + } + this.length = clen; + } + + private float map(float u) + { + float targetLength = u * this.arcLengths[(int)this.len]; + int low = 0; + int high = (int)this.len; + int index = 0; + while (low < high) + { + index = low + ((int)((high - low) / 2.0f) | 0); + if (this.arcLengths[index] < targetLength) + { + low = index + 1; + } + else + { + high = index; + } + } + if (this.arcLengths[index] > targetLength) + index--; + if (index < 0) + index = 0; + + return (index + (targetLength - arcLengths[index]) / (arcLengths[index + 1] - arcLengths[index])) / this.len; + } + + private Vector3 bezierPoint(float t) + { + return ((aa * t + (bb)) * t + cc) * t + a; + } + + public Vector3 point(float t) + { + return bezierPoint(map(t)); + } +} + +/** +* Manually animate along a bezier path with this class +* @class LTBezierPath +* @constructor +* @param {Vector3 Array} pts A set of points that define one or many bezier paths (the paths should be passed in multiples of 4, which correspond to each individual bezier curve)
+* It goes in the order: startPoint,endControl,startControl,endPoint - Note: the control for the end and start are reversed! This is just a *quirk* of the API.
+* +* @example +* LTBezierPath ltPath = new LTBezierPath( new Vector3[] { new Vector3(0f,0f,0f),new Vector3(1f,0f,0f), new Vector3(1f,0f,0f), new Vector3(1f,1f,0f)} );

+* LeanTween.move(lt, ltPath.vec3, 4.0f).setOrientToPath(true).setDelay(1f).setEase(LeanTweenType.easeInOutQuad); // animate
+* Vector3 pt = ltPath.point( 0.6f ); // retrieve a point along the path +*/ +public class LTBezierPath +{ + public Vector3[] pts; + public float length; + public bool orientToPath; + public bool orientToPath2d; + + private LTBezier[] beziers; + private float[] lengthRatio; + private int currentBezier = 0, previousBezier = 0; + + public LTBezierPath() { } + public LTBezierPath(Vector3[] pts_) + { + setPoints(pts_); + } + + public void setPoints(Vector3[] pts_) + { + if (pts_.Length < 4) + LeanTween.logError("LeanTween - When passing values for a vector path, you must pass four or more values!"); + if (pts_.Length % 4 != 0) + LeanTween.logError("LeanTween - When passing values for a vector path, they must be in sets of four: controlPoint1, controlPoint2, endPoint2, controlPoint2, controlPoint2..."); + + pts = pts_; + + int k = 0; + beziers = new LTBezier[pts.Length / 4]; + lengthRatio = new float[beziers.Length]; + int i; + length = 0; + for (i = 0; i < pts.Length; i += 4) + { + beziers[k] = new LTBezier(pts[i + 0], pts[i + 2], pts[i + 1], pts[i + 3], 0.05f); + length += beziers[k].length; + k++; + } + // Debug.Log("beziers.Length:"+beziers.Length + " beziers:"+beziers); + for (i = 0; i < beziers.Length; i++) + { + lengthRatio[i] = beziers[i].length / length; + } + } + + /** + * @property {float} distance distance of the path (in unity units) + */ + public float distance + { + get + { + return length; + } + } + + /** + * Retrieve a point along a path + * + * @method point + * @param {float} ratio:float ratio of the point along the path you wish to receive (0-1) + * @return {Vector3} Vector3 position of the point along the path + * @example + * transform.position = ltPath.point( 0.6f ); + */ + public Vector3 point(float ratio) + { + float added = 0.0f; + for (int i = 0; i < lengthRatio.Length; i++) + { + added += lengthRatio[i]; + if (added >= ratio) + return beziers[i].point((ratio - (added - lengthRatio[i])) / lengthRatio[i]); + } + return beziers[lengthRatio.Length - 1].point(1.0f); + } + + public void place2d(Transform transform, float ratio) + { + transform.position = point(ratio); + ratio += 0.001f; + if (ratio <= 1.0f) + { + Vector3 v3Dir = point(ratio) - transform.position; + float angle = Mathf.Atan2(v3Dir.y, v3Dir.x) * Mathf.Rad2Deg; + transform.eulerAngles = new Vector3(0, 0, angle); + } + } + + public void placeLocal2d(Transform transform, float ratio) + { + transform.localPosition = point(ratio); + ratio += 0.001f; + if (ratio <= 1.0f) + { + Vector3 v3Dir = point(ratio) - transform.localPosition; + float angle = Mathf.Atan2(v3Dir.y, v3Dir.x) * Mathf.Rad2Deg; + transform.localEulerAngles = new Vector3(0, 0, angle); + } + } + + /** + * Place an object along a certain point on the path (facing the direction perpendicular to the path) + * + * @method place + * @param {Transform} transform:Transform the transform of the object you wish to place along the path + * @param {float} ratio:float ratio of the point along the path you wish to receive (0-1) + * @example + * ltPath.place( transform, 0.6f ); + */ + public void place(Transform transform, float ratio) + { + place(transform, ratio, Vector3.up); + + } + + /** + * Place an object along a certain point on the path, with it facing a certain direction perpendicular to the path + * + * @method place + * @param {Transform} transform:Transform the transform of the object you wish to place along the path + * @param {float} ratio:float ratio of the point along the path you wish to receive (0-1) + * @param {Vector3} rotation:Vector3 the direction in which to place the transform ex: Vector3.up + * @example + * ltPath.place( transform, 0.6f, Vector3.left ); + */ + public void place(Transform transform, float ratio, Vector3 worldUp) + { + transform.position = point(ratio); + ratio += 0.001f; + if (ratio <= 1.0f) + transform.LookAt(point(ratio), worldUp); + + } + + /** + * Place an object along a certain point on the path (facing the direction perpendicular to the path) - Local Space, not world-space + * + * @method placeLocal + * @param {Transform} transform:Transform the transform of the object you wish to place along the path + * @param {float} ratio:float ratio of the point along the path you wish to receive (0-1) + * @example + * ltPath.placeLocal( transform, 0.6f ); + */ + public void placeLocal(Transform transform, float ratio) + { + placeLocal(transform, ratio, Vector3.up); + } + + /** + * Place an object along a certain point on the path, with it facing a certain direction perpendicular to the path - Local Space, not world-space + * + * @method placeLocal + * @param {Transform} transform:Transform the transform of the object you wish to place along the path + * @param {float} ratio:float ratio of the point along the path you wish to receive (0-1) + * @param {Vector3} rotation:Vector3 the direction in which to place the transform ex: Vector3.up + * @example + * ltPath.placeLocal( transform, 0.6f, Vector3.left ); + */ + public void placeLocal(Transform transform, float ratio, Vector3 worldUp) + { + // Debug.Log("place ratio:" + ratio + " greater:"+(ratio>1f)); + ratio = Mathf.Clamp01(ratio); + transform.localPosition = point(ratio); + // Debug.Log("ratio:" + ratio + " +:" + (ratio + 0.001f)); + ratio = Mathf.Clamp01(ratio + 0.001f); + + if (ratio <= 1.0f) + transform.LookAt(transform.parent.TransformPoint(point(ratio)), worldUp); + } + + public void gizmoDraw(float t = -1.0f) + { + Vector3 prevPt = point(0); + + for (int i = 1; i <= 120; i++) + { + float pm = (float)i / 120f; + Vector3 currPt2 = point(pm); + //Gizmos.color = new Color(UnityEngine.Random.Range(0f,1f),UnityEngine.Random.Range(0f,1f),UnityEngine.Random.Range(0f,1f),1); + Gizmos.color = (previousBezier == currentBezier) ? Color.magenta : Color.grey; + Gizmos.DrawLine(currPt2, prevPt); + prevPt = currPt2; + previousBezier = currentBezier; + } + } + + /** + * Retrieve the closest ratio near the point + * + * @method ratioAtPoint + * @param {Vector3} point:Vector3 given a current location it makes the best approximiation of where it is along the path ratio-wise (0-1) + * @return {float} float of ratio along the path + * @example + * ratioIter = ltBezier.ratioAtPoint( transform.position ); + */ + public float ratioAtPoint(Vector3 pt, float precision = 0.01f) + { + float closestDist = float.MaxValue; + int closestI = 0; + int maxIndex = Mathf.RoundToInt(1f / precision); + for (int i = 0; i < maxIndex; i++) + { + float ratio = (float)i / (float)maxIndex; + float dist = Vector3.Distance(pt, point(ratio)); + // Debug.Log("i:"+i+" dist:"+dist); + if (dist < closestDist) + { + closestDist = dist; + closestI = i; + } + } + //Debug.Log("closestI:"+closestI+" maxIndex:"+maxIndex); + return (float)closestI / (float)(maxIndex); + } +} + +/** +* Animate along a set of points that need to be in the format: controlPoint, point1, point2.... pointLast, endControlPoint Move a GameObject to a certain location +* @class LTSpline +* @constructor +* @param {Vector3 Array} pts A set of points that define the points the path will pass through (starting with starting control point, and ending with a control point)
+Note: The first and last item just define the angle of the end points, they are not actually used in the spline path itself. If you do not care about the angle you can jus set the first two items and last two items as the same value. +* @example +* LTSpline ltSpline = new LTSpline( new Vector3[] { new Vector3(0f,0f,0f),new Vector3(0f,0f,0f), new Vector3(0f,0.5f,0f), new Vector3(1f,1f,0f), new Vector3(1f,1f,0f)} );

+* LeanTween.moveSpline(lt, ltSpline.vec3, 4.0f).setOrientToPath(true).setDelay(1f).setEase(LeanTweenType.easeInOutQuad); // animate
+* Vector3 pt = ltSpline.point( 0.6f ); // retrieve a point along the path +*/ +[System.Serializable] +public class LTSpline +{ + public static int DISTANCE_COUNT = 3; // increase for a more accurate constant speed + public static int SUBLINE_COUNT = 20; // increase for a more accurate smoothing of the curves into lines + + /** + * @property {float} distance distance of the spline (in unity units) + */ + public float distance = 0f; + + public bool constantSpeed = true; + + public Vector3[] pts; + [System.NonSerialized] + public Vector3[] ptsAdj; + public int ptsAdjLength; + public bool orientToPath; + public bool orientToPath2d; + private int numSections; + private int currPt; + + public LTSpline(Vector3[] pts) + { + init(pts, true); + } + + public LTSpline(Vector3[] pts, bool constantSpeed) + { + this.constantSpeed = constantSpeed; + init(pts, constantSpeed); + } + + private void init(Vector3[] pts, bool constantSpeed) + { + if (pts.Length < 4) + { + LeanTween.logError("LeanTween - When passing values for a spline path, you must pass four or more values!"); + return; + } + + this.pts = new Vector3[pts.Length]; + System.Array.Copy(pts, this.pts, pts.Length); + + numSections = pts.Length - 3; + + float minSegment = float.PositiveInfinity; + Vector3 earlierPoint = this.pts[1]; + float totalDistance = 0f; + for (int i = 1; i < this.pts.Length - 1; i++) + { + // float pointDistance = (this.pts[i]-earlierPoint).sqrMagnitude; + float pointDistance = Vector3.Distance(this.pts[i], earlierPoint); + //Debug.Log("pointDist:"+pointDistance); + if (pointDistance < minSegment) + { + minSegment = pointDistance; + } + + totalDistance += pointDistance; + } + + if (constantSpeed) + { + minSegment = totalDistance / (numSections * SUBLINE_COUNT); + //Debug.Log("minSegment:"+minSegment+" numSections:"+numSections); + + float minPrecision = minSegment / SUBLINE_COUNT; // number of subdivisions in each segment + int precision = (int)Mathf.Ceil(totalDistance / minPrecision) * DISTANCE_COUNT; + // Debug.Log("precision:"+precision); + if (precision <= 1) // precision has to be greater than one + precision = 2; + + ptsAdj = new Vector3[precision]; + earlierPoint = interp(0f); + int num = 1; + ptsAdj[0] = earlierPoint; + distance = 0f; + for (int i = 0; i < precision + 1; i++) + { + float fract = ((float)(i)) / precision; + // Debug.Log("fract:"+fract); + Vector3 point = interp(fract); + float dist = Vector3.Distance(point, earlierPoint); + + // float dist = (point-earlierPoint).sqrMagnitude; + if (dist >= minPrecision || fract >= 1.0f) + { + ptsAdj[num] = point; + distance += dist; // only add it to the total distance once we know we are adding it as an adjusted point + + earlierPoint = point; + // Debug.Log("fract:"+fract+" point:"+point); + num++; + } + } + // make sure there is a point at the very end + /*num++; + Vector3 endPoint = interp( 1f ); + ptsAdj[num] = endPoint;*/ + // Debug.Log("fract 1f endPoint:"+endPoint); + + ptsAdjLength = num; + } + // Debug.Log("map 1f:"+map(1f)+" end:"+ptsAdj[ ptsAdjLength-1 ]); + + // Debug.Log("ptsAdjLength:"+ptsAdjLength+" minPrecision:"+minPrecision+" precision:"+precision); + } + + public Vector3 map(float u) + { + if (u >= 1f) + return pts[pts.Length - 2]; + float t = u * (ptsAdjLength - 1); + int first = (int)Mathf.Floor(t); + int next = (int)Mathf.Ceil(t); + + if (first < 0) + first = 0; + + Vector3 val = ptsAdj[first]; + + + Vector3 nextVal = ptsAdj[next]; + float diff = t - first; + + // Debug.Log("u:"+u+" val:"+val +" nextVal:"+nextVal+" diff:"+diff+" first:"+first+" next:"+next); + + val = val + (nextVal - val) * diff; + + return val; + } + + public Vector3 interp(float t) + { + currPt = Mathf.Min(Mathf.FloorToInt(t * (float)numSections), numSections - 1); + float u = t * (float)numSections - (float)currPt; + + //Debug.Log("currPt:"+currPt+" numSections:"+numSections+" pts.Length :"+pts.Length ); + Vector3 a = pts[currPt]; + Vector3 b = pts[currPt + 1]; + Vector3 c = pts[currPt + 2]; + Vector3 d = pts[currPt + 3]; + + Vector3 val = (.5f * ( + (-a + 3f * b - 3f * c + d) * (u * u * u) + + (2f * a - 5f * b + 4f * c - d) * (u * u) + + (-a + c) * u + + 2f * b)); + // Debug.Log("currPt:"+currPt+" t:"+t+" val.x"+val.x+" y:"+val.y+" z:"+val.z); + + return val; + } + + /** + * Retrieve a point along a path Move a GameObject to a certain location + * + * @method ratioAtPoint + * @param {Vector3} point:Vector3 given a current location it makes the best approximiation of where it is along the path ratio-wise (0-1) + * @return {float} float of ratio along the path + * @example + * ratioIter = ltSpline.ratioAtPoint( transform.position ); + */ + public float ratioAtPoint(Vector3 pt) + { + float closestDist = float.MaxValue; + int closestI = 0; + for (int i = 0; i < ptsAdjLength; i++) + { + float dist = Vector3.Distance(pt, ptsAdj[i]); + // Debug.Log("i:"+i+" dist:"+dist); + if (dist < closestDist) + { + closestDist = dist; + closestI = i; + } + } + // Debug.Log("closestI:"+closestI+" ptsAdjLength:"+ptsAdjLength); + return (float)closestI / (float)(ptsAdjLength - 1); + } + + /** + * Retrieve a point along a path Move a GameObject to a certain location + * + * @method point + * @param {float} ratio:float ratio of the point along the path you wish to receive (0-1) + * @return {Vector3} Vector3 position of the point along the path + * @example + * transform.position = ltSpline.point( 0.6f ); + */ + public Vector3 point(float ratio) + { + float t = ratio > 1f ? 1f : ratio; + return constantSpeed ? map(t) : interp(t); + } + + public void place2d(Transform transform, float ratio) + { + transform.position = point(ratio); + ratio += 0.001f; + if (ratio <= 1.0f) + { + Vector3 v3Dir = point(ratio) - transform.position; + float angle = Mathf.Atan2(v3Dir.y, v3Dir.x) * Mathf.Rad2Deg; + transform.eulerAngles = new Vector3(0, 0, angle); + } + } + + public void placeLocal2d(Transform transform, float ratio) + { + Transform trans = transform.parent; + if (trans == null) + { // this has no parent, just do a regular transform + place2d(transform, ratio); + return; + } + transform.localPosition = point(ratio); + ratio += 0.001f; + if (ratio <= 1.0f) + { + Vector3 ptAhead = point(ratio);//trans.TransformPoint( ); + Vector3 v3Dir = ptAhead - transform.localPosition; + float angle = Mathf.Atan2(v3Dir.y, v3Dir.x) * Mathf.Rad2Deg; + transform.localEulerAngles = new Vector3(0, 0, angle); + } + } + + + /** + * Place an object along a certain point on the path (facing the direction perpendicular to the path) Move a GameObject to a certain location + * + * @method place + * @param {Transform} transform:Transform the transform of the object you wish to place along the path + * @param {float} ratio:float ratio of the point along the path you wish to receive (0-1) + * @example + * ltPath.place( transform, 0.6f ); + */ + public void place(Transform transform, float ratio) + { + place(transform, ratio, Vector3.up); + } + + /** + * Place an object along a certain point on the path, with it facing a certain direction perpendicular to the path Move a GameObject to a certain location + * + * @method place + * @param {Transform} transform:Transform the transform of the object you wish to place along the path + * @param {float} ratio:float ratio of the point along the path you wish to receive (0-1) + * @param {Vector3} rotation:Vector3 the direction in which to place the transform ex: Vector3.up + * @example + * ltPath.place( transform, 0.6f, Vector3.left ); + */ + public void place(Transform transform, float ratio, Vector3 worldUp) + { + // ratio = Mathf.Repeat(ratio, 1.0f); // make sure ratio is always between 0-1 + transform.position = point(ratio); + ratio += 0.001f; + if (ratio <= 1.0f) + transform.LookAt(point(ratio), worldUp); + + } + + /** + * Place an object along a certain point on the path (facing the direction perpendicular to the path) - Local Space, not world-space Move a GameObject to a certain location + * + * @method placeLocal + * @param {Transform} transform:Transform the transform of the object you wish to place along the path + * @param {float} ratio:float ratio of the point along the path you wish to receive (0-1) + * @example + * ltPath.placeLocal( transform, 0.6f ); + */ + public void placeLocal(Transform transform, float ratio) + { + placeLocal(transform, ratio, Vector3.up); + } + + /** + * Place an object along a certain point on the path, with it facing a certain direction perpendicular to the path - Local Space, not world-space Move a GameObject to a certain location + * + * @method placeLocal + * @param {Transform} transform:Transform the transform of the object you wish to place along the path + * @param {float} ratio:float ratio of the point along the path you wish to receive (0-1) + * @param {Vector3} rotation:Vector3 the direction in which to place the transform ex: Vector3.up + * @example + * ltPath.placeLocal( transform, 0.6f, Vector3.left ); + */ + public void placeLocal(Transform transform, float ratio, Vector3 worldUp) + { + transform.localPosition = point(ratio); + ratio += 0.001f; + if (ratio <= 1.0f) + transform.LookAt(transform.parent.TransformPoint(point(ratio)), worldUp); + } + + public void gizmoDraw(float t = -1.0f) + { + if (ptsAdj == null || ptsAdj.Length <= 0) + return; + + Vector3 prevPt = ptsAdj[0]; + + for (int i = 0; i < ptsAdjLength; i++) + { + Vector3 currPt2 = ptsAdj[i]; + // Debug.Log("currPt2:"+currPt2); + //Gizmos.color = new Color(UnityEngine.Random.Range(0f,1f),UnityEngine.Random.Range(0f,1f),UnityEngine.Random.Range(0f,1f),1); + Gizmos.DrawLine(prevPt, currPt2); + prevPt = currPt2; + } + } + + public void drawGizmo(Color color) + { + if (this.ptsAdjLength >= 4) + { + + Vector3 prevPt = this.ptsAdj[0]; + + Color colorBefore = Gizmos.color; + Gizmos.color = color; + for (int i = 0; i < this.ptsAdjLength; i++) + { + Vector3 currPt2 = this.ptsAdj[i]; + // Debug.Log("currPt2:"+currPt2); + + Gizmos.DrawLine(prevPt, currPt2); + prevPt = currPt2; + } + Gizmos.color = colorBefore; + } + } + + public static void drawGizmo(Transform[] arr, Color color) + { + if (arr.Length >= 4) + { + Vector3[] vec3s = new Vector3[arr.Length]; + for (int i = 0; i < arr.Length; i++) + { + vec3s[i] = arr[i].position; + } + LTSpline spline = new LTSpline(vec3s); + Vector3 prevPt = spline.ptsAdj[0]; + + Color colorBefore = Gizmos.color; + Gizmos.color = color; + for (int i = 0; i < spline.ptsAdjLength; i++) + { + Vector3 currPt2 = spline.ptsAdj[i]; + // Debug.Log("currPt2:"+currPt2); + + Gizmos.DrawLine(prevPt, currPt2); + prevPt = currPt2; + } + Gizmos.color = colorBefore; + } + } + + + public static void drawLine(Transform[] arr, float width, Color color) + { + if (arr.Length >= 4) + { + + } + } + + /*public Vector3 Velocity(float t) { + t = map( t ); + + int numSections = pts.Length - 3; + int currPt = Mathf.Min(Mathf.FloorToInt(t * (float) numSections), numSections - 1); + float u = t * (float) numSections - (float) currPt; + + Vector3 a = pts[currPt]; + Vector3 b = pts[currPt + 1]; + Vector3 c = pts[currPt + 2]; + Vector3 d = pts[currPt + 3]; + + return 1.5f * (-a + 3f * b - 3f * c + d) * (u * u) + + (2f * a -5f * b + 4f * c - d) * u + + .5f * c - .5f * a; + }*/ + + public void drawLinesGLLines(Material outlineMaterial, Color color, float width) + { + GL.PushMatrix(); + outlineMaterial.SetPass(0); + GL.LoadPixelMatrix(); + GL.Begin(GL.LINES); + GL.Color(color); + + if (constantSpeed) + { + if (this.ptsAdjLength >= 4) + { + + Vector3 prevPt = this.ptsAdj[0]; + + for (int i = 0; i < this.ptsAdjLength; i++) + { + Vector3 currPt2 = this.ptsAdj[i]; + GL.Vertex(prevPt); + GL.Vertex(currPt2); + + prevPt = currPt2; + } + } + + } + else + { + if (this.pts.Length >= 4) + { + + Vector3 prevPt = this.pts[0]; + + float split = 1f / ((float)this.pts.Length * 10f); + + float iter = 0f; + while (iter < 1f) + { + float at = iter / 1f; + Vector3 currPt2 = interp(at); + // Debug.Log("currPt2:"+currPt2); + + GL.Vertex(prevPt); + GL.Vertex(currPt2); + + prevPt = currPt2; + + iter += split; + } + } + } + + + GL.End(); + GL.PopMatrix(); + + } + + public Vector3[] generateVectors() + { + if (this.pts.Length >= 4) + { + List meshPoints = new List(); + Vector3 prevPt = this.pts[0]; + meshPoints.Add(prevPt); + + float split = 1f / ((float)this.pts.Length * 10f); + + float iter = 0f; + while (iter < 1f) + { + float at = iter / 1f; + Vector3 currPt2 = interp(at); + // Debug.Log("currPt2:"+currPt2); + + // GL.Vertex(prevPt); + // GL.Vertex(currPt2); + meshPoints.Add(currPt2); + + // prevPt = currPt2; + + iter += split; + } + + meshPoints.ToArray(); + } + return null; + } +} + +/** +* Animate GUI Elements by creating this object and passing the *.rect variable to the GUI method

+* Example Javascript:
var bRect:LTRect = new LTRect( 0, 0, 100, 50 );
+* LeanTween.scale( bRect, Vector2(bRect.rect.width, bRect.rect.height) * 1.3, 0.25 );
+* function OnGUI(){
+*   if(GUI.Button(bRect.rect, "Scale")){ }
+* }
+*
+* Example C#:
+* LTRect bRect = new LTRect( 0f, 0f, 100f, 50f );
+* LeanTween.scale( bRect, new Vector2(150f,75f), 0.25f );
+* void OnGUI(){
+*   if(GUI.Button(bRect.rect, "Scale")){ }
+* }
+* +* @class LTRect +* @constructor +* @param {float} x:float X location +* @param {float} y:float Y location +* @param {float} width:float Width +* @param {float} height:float Height +* @param {float} alpha:float (Optional) initial alpha amount (0-1) +* @param {float} rotation:float (Optional) initial rotation in degrees (0-360) +*/ + +[System.Serializable] +public class LTRect : System.Object +{ + /** + * Pass this value to the GUI Methods + * + * @property rect + * @type {Rect} rect:Rect Rect object that controls the positioning and size + */ + public Rect _rect; + public float alpha = 1f; + public float rotation; + public Vector2 pivot; + public Vector2 margin; + public Rect relativeRect = new Rect(0f, 0f, float.PositiveInfinity, float.PositiveInfinity); + + public bool rotateEnabled; + [HideInInspector] + public bool rotateFinished; + public bool alphaEnabled; + public string labelStr; + public LTGUI.Element_Type type; + public GUIStyle style; + public bool useColor = false; + public Color color = Color.white; + public bool fontScaleToFit; + public bool useSimpleScale; + public bool sizeByHeight; + + public Texture texture; + + private int _id = -1; + [HideInInspector] + public int counter; + + public static bool colorTouched; + + public LTRect() + { + reset(); + this.rotateEnabled = this.alphaEnabled = true; + _rect = new Rect(0f, 0f, 1f, 1f); + } + + public LTRect(Rect rect) + { + _rect = rect; + reset(); + } + + public LTRect(float x, float y, float width, float height) + { + _rect = new Rect(x, y, width, height); + this.alpha = 1.0f; + this.rotation = 0.0f; + this.rotateEnabled = this.alphaEnabled = false; + } + + public LTRect(float x, float y, float width, float height, float alpha) + { + _rect = new Rect(x, y, width, height); + this.alpha = alpha; + this.rotation = 0.0f; + this.rotateEnabled = this.alphaEnabled = false; + } + + public LTRect(float x, float y, float width, float height, float alpha, float rotation) + { + _rect = new Rect(x, y, width, height); + this.alpha = alpha; + this.rotation = rotation; + this.rotateEnabled = this.alphaEnabled = false; + if (rotation != 0.0f) + { + this.rotateEnabled = true; + resetForRotation(); + } + } + + public bool hasInitiliazed + { + get + { + return _id != -1; + } + } + + public int id + { + get + { + int toId = _id | counter << 16; + + /*uint backId = toId & 0xFFFF; + uint backCounter = toId >> 16; + if(_id!=backId || backCounter!=counter){ + Debug.LogError("BAD CONVERSION toId:"+_id); + }*/ + + return toId; + } + } + + public void setId(int id, int counter) + { + this._id = id; + this.counter = counter; + } + + public void reset() + { + this.alpha = 1.0f; + this.rotation = 0.0f; + this.rotateEnabled = this.alphaEnabled = false; + this.margin = Vector2.zero; + this.sizeByHeight = false; + this.useColor = false; + } + + public void resetForRotation() + { + Vector3 scale = new Vector3(GUI.matrix[0, 0], GUI.matrix[1, 1], GUI.matrix[2, 2]); + if (pivot == Vector2.zero) + { + pivot = new Vector2((_rect.x + ((_rect.width) * 0.5f)) * scale.x + GUI.matrix[0, 3], (_rect.y + ((_rect.height) * 0.5f)) * scale.y + GUI.matrix[1, 3]); + } + } + + public float x + { + get { return _rect.x; } + set { _rect.x = value; } + } + + public float y + { + get { return _rect.y; } + set { _rect.y = value; } + } + + public float width + { + get { return _rect.width; } + set { _rect.width = value; } + } + + public float height + { + get { return _rect.height; } + set { _rect.height = value; } + } + + public Rect rect + { + + get + { + if (colorTouched) + { + colorTouched = false; + GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, 1.0f); + } + if (rotateEnabled) + { + if (rotateFinished) + { + rotateFinished = false; + rotateEnabled = false; + //this.rotation = 0.0f; + pivot = Vector2.zero; + } + else + { + GUIUtility.RotateAroundPivot(rotation, pivot); + } + } + if (alphaEnabled) + { + GUI.color = new Color(GUI.color.r, GUI.color.g, GUI.color.b, alpha); + colorTouched = true; + } + if (fontScaleToFit) + { + if (this.useSimpleScale) + { + style.fontSize = (int)(_rect.height * this.relativeRect.height); + } + else + { + style.fontSize = (int)_rect.height; + } + } + return _rect; + } + + set + { + _rect = value; + } + } + + public LTRect setStyle(GUIStyle style) + { + this.style = style; + return this; + } + + public LTRect setFontScaleToFit(bool fontScaleToFit) + { + this.fontScaleToFit = fontScaleToFit; + return this; + } + + public LTRect setColor(Color color) + { + this.color = color; + this.useColor = true; + return this; + } + + public LTRect setAlpha(float alpha) + { + this.alpha = alpha; + return this; + } + + public LTRect setLabel(String str) + { + this.labelStr = str; + return this; + } + + public LTRect setUseSimpleScale(bool useSimpleScale, Rect relativeRect) + { + this.useSimpleScale = useSimpleScale; + this.relativeRect = relativeRect; + return this; + } + + public LTRect setUseSimpleScale(bool useSimpleScale) + { + this.useSimpleScale = useSimpleScale; + this.relativeRect = new Rect(0f, 0f, Screen.width, Screen.height); + return this; + } + + public LTRect setSizeByHeight(bool sizeByHeight) + { + this.sizeByHeight = sizeByHeight; + return this; + } + + public override string ToString() + { + return "x:" + _rect.x + " y:" + _rect.y + " width:" + _rect.width + " height:" + _rect.height; + } +} + +/** +* Object that describes the event to an event listener +* @class LTEvent +* @constructor +* @param {object} data:object Data that has been passed from the dispatchEvent method +*/ +public class LTEvent +{ + public int id; + public object data; + + public LTEvent(int id, object data) + { + this.id = id; + this.data = data; + } +} + +public class LTGUI +{ + public static int RECT_LEVELS = 5; + public static int RECTS_PER_LEVEL = 10; + public static int BUTTONS_MAX = 24; + + private static LTRect[] levels; + private static int[] levelDepths; + private static Rect[] buttons; + private static int[] buttonLevels; + private static int[] buttonLastFrame; + private static LTRect r; + private static Color color = Color.white; + private static bool isGUIEnabled = false; + private static int global_counter = 0; + + public enum Element_Type + { + Texture, + Label + } + + public static void init() + { + if (levels == null) + { + levels = new LTRect[RECT_LEVELS * RECTS_PER_LEVEL]; + levelDepths = new int[RECT_LEVELS]; + } + } + + public static void initRectCheck() + { + if (buttons == null) + { + buttons = new Rect[BUTTONS_MAX]; + buttonLevels = new int[BUTTONS_MAX]; + buttonLastFrame = new int[BUTTONS_MAX]; + for (int i = 0; i < buttonLevels.Length; i++) + { + buttonLevels[i] = -1; + } + } + } + + public static void reset() + { + if (isGUIEnabled) + { + isGUIEnabled = false; + for (int i = 0; i < levels.Length; i++) + { + levels[i] = null; + } + + for (int i = 0; i < levelDepths.Length; i++) + { + levelDepths[i] = 0; + } + } + } + + public static void update(int updateLevel) + { + if (isGUIEnabled) + { + init(); + if (levelDepths[updateLevel] > 0) + { + color = GUI.color; + int baseI = updateLevel * RECTS_PER_LEVEL; + int maxLoop = baseI + levelDepths[updateLevel];// RECTS_PER_LEVEL;//; + + for (int i = baseI; i < maxLoop; i++) + { + r = levels[i]; + // Debug.Log("r:"+r+" i:"+i); + if (r != null /*&& checkOnScreen(r.rect)*/) + { + //Debug.Log("label:"+r.labelStr+" textColor:"+r.style.normal.textColor); + if (r.useColor) + GUI.color = r.color; + if (r.type == Element_Type.Label) + { + if (r.style != null) + GUI.skin.label = r.style; + if (r.useSimpleScale) + { + GUI.Label(new Rect((r.rect.x + r.margin.x + r.relativeRect.x) * r.relativeRect.width, (r.rect.y + r.margin.y + r.relativeRect.y) * r.relativeRect.height, r.rect.width * r.relativeRect.width, r.rect.height * r.relativeRect.height), r.labelStr); + } + else + { + GUI.Label(new Rect(r.rect.x + r.margin.x, r.rect.y + r.margin.y, r.rect.width, r.rect.height), r.labelStr); + } + } + else if (r.type == Element_Type.Texture && r.texture != null) + { + Vector2 size = r.useSimpleScale ? new Vector2(0f, r.rect.height * r.relativeRect.height) : new Vector2(r.rect.width, r.rect.height); + if (r.sizeByHeight) + { + size.x = (float)r.texture.width / (float)r.texture.height * size.y; + } + if (r.useSimpleScale) + { + GUI.DrawTexture(new Rect((r.rect.x + r.margin.x + r.relativeRect.x) * r.relativeRect.width, (r.rect.y + r.margin.y + r.relativeRect.y) * r.relativeRect.height, size.x, size.y), r.texture); + } + else + { + GUI.DrawTexture(new Rect(r.rect.x + r.margin.x, r.rect.y + r.margin.y, size.x, size.y), r.texture); + } + } + } + } + GUI.color = color; + } + } + } + + public static bool checkOnScreen(Rect rect) + { + bool offLeft = rect.x + rect.width < 0f; + bool offRight = rect.x > Screen.width; + bool offBottom = rect.y > Screen.height; + bool offTop = rect.y + rect.height < 0f; + + return !(offLeft || offRight || offBottom || offTop); + } + + public static void destroy(int id) + { + int backId = id & 0xFFFF; + int backCounter = id >> 16; + if (id >= 0 && levels[backId] != null && levels[backId].hasInitiliazed && levels[backId].counter == backCounter) + levels[backId] = null; + } + + public static void destroyAll(int depth) + { // clears all gui elements on depth + int maxLoop = depth * RECTS_PER_LEVEL + RECTS_PER_LEVEL; + for (int i = depth * RECTS_PER_LEVEL; levels != null && i < maxLoop; i++) + { + levels[i] = null; + } + } + + public static LTRect label(Rect rect, string label, int depth) + { + return LTGUI.label(new LTRect(rect), label, depth); + } + + public static LTRect label(LTRect rect, string label, int depth) + { + rect.type = Element_Type.Label; + rect.labelStr = label; + return element(rect, depth); + } + + public static LTRect texture(Rect rect, Texture texture, int depth) + { + return LTGUI.texture(new LTRect(rect), texture, depth); + } + + public static LTRect texture(LTRect rect, Texture texture, int depth) + { + rect.type = Element_Type.Texture; + rect.texture = texture; + return element(rect, depth); + } + + public static LTRect element(LTRect rect, int depth) + { + isGUIEnabled = true; + init(); + int maxLoop = depth * RECTS_PER_LEVEL + RECTS_PER_LEVEL; + int k = 0; + if (rect != null) + { + destroy(rect.id); + } + if (rect.type == LTGUI.Element_Type.Label && rect.style != null) + { + if (rect.style.normal.textColor.a <= 0f) + { + Debug.LogWarning("Your GUI normal color has an alpha of zero, and will not be rendered."); + } + } + if (rect.relativeRect.width == float.PositiveInfinity) + { + rect.relativeRect = new Rect(0f, 0f, Screen.width, Screen.height); + } + for (int i = depth * RECTS_PER_LEVEL; i < maxLoop; i++) + { + r = levels[i]; + if (r == null) + { + r = rect; + r.rotateEnabled = true; + r.alphaEnabled = true; + r.setId(i, global_counter); + levels[i] = r; + // Debug.Log("k:"+k+ " maxDepth:"+levelDepths[depth]); + if (k >= levelDepths[depth]) + { + levelDepths[depth] = k + 1; + } + global_counter++; + return r; + } + k++; + } + + Debug.LogError("You ran out of GUI Element spaces"); + + return null; + } + + public static bool hasNoOverlap(Rect rect, int depth) + { + initRectCheck(); + bool hasNoOverlap = true; + bool wasAddedToList = false; + for (int i = 0; i < buttonLevels.Length; i++) + { + // Debug.Log("buttonLastFrame["+i+"]:"+buttonLastFrame[i]); + //Debug.Log("buttonLevels["+i+"]:"+buttonLevels[i]); + if (buttonLevels[i] >= 0) + { + //Debug.Log("buttonLastFrame["+i+"]:"+buttonLastFrame[i]+" Time.frameCount:"+Time.frameCount); + if (buttonLastFrame[i] + 1 < Time.frameCount) + { // It has to have been visible within the current, or + buttonLevels[i] = -1; + // Debug.Log("resetting i:"+i); + } + else + { + //if(buttonLevels[i]>=0) + // Debug.Log("buttonLevels["+i+"]:"+buttonLevels[i]); + if (buttonLevels[i] > depth) + { + /*if(firstTouch().x > 0){ + Debug.Log("buttons["+i+"]:"+buttons[i] + " firstTouch:"); + Debug.Log(firstTouch()); + Debug.Log(buttonLevels[i]); + }*/ + if (pressedWithinRect(buttons[i])) + { + hasNoOverlap = false; // there is an overlapping button that is higher + } + } + } + } + + if (wasAddedToList == false && buttonLevels[i] < 0) + { + wasAddedToList = true; + buttonLevels[i] = depth; + buttons[i] = rect; + buttonLastFrame[i] = Time.frameCount; + } + } + + return hasNoOverlap; + } + + public static bool pressedWithinRect(Rect rect) + { + Vector2 vec2 = firstTouch(); + if (vec2.x < 0f) + return false; + float vecY = Screen.height - vec2.y; + return (vec2.x > rect.x && vec2.x < rect.x + rect.width && vecY > rect.y && vecY < rect.y + rect.height); + } + + public static bool checkWithinRect(Vector2 vec2, Rect rect) + { + vec2.y = Screen.height - vec2.y; + return (vec2.x > rect.x && vec2.x < rect.x + rect.width && vec2.y > rect.y && vec2.y < rect.y + rect.height); + } + + public static Vector2 firstTouch() + { + if (Input.touchCount > 0) + { + return Input.touches[0].position; + } + else if (Input.GetMouseButton(0)) + { + return Input.mousePosition; + } + + return new Vector2(Mathf.NegativeInfinity, Mathf.NegativeInfinity); + } + +} + +namespace DentedPixel { public class LeanDummy { } } +//} diff --git a/KFAttached/LeanTween/Framework/LeanTween.cs.meta b/KFAttached/LeanTween/Framework/LeanTween.cs.meta new file mode 100644 index 0000000..33c8c76 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LeanTween.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9c2f4b27196f84954b44753aaac214bb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/LeanTween/Framework/LeanTweenExt.cs b/KFAttached/LeanTween/Framework/LeanTweenExt.cs new file mode 100644 index 0000000..6c14ba2 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LeanTweenExt.cs @@ -0,0 +1,188 @@ +using System; +using UnityEngine; + +public static class LeanTweenExt +{ + //LeanTween.addListener + //LeanTween.alpha + public static LTDescr LeanAlpha(this GameObject gameObject, float to, float time) { return LeanTween.alpha(gameObject, to, time); } + //LeanTween.alphaCanvas + public static LTDescr LeanAlphaVertex(this GameObject gameObject, float to, float time) { return LeanTween.alphaVertex(gameObject, to, time); } + //LeanTween.alpha (RectTransform) + public static LTDescr LeanAlpha(this RectTransform rectTransform, float to, float time) { return LeanTween.alpha(rectTransform, to, time); } + //LeanTween.alphaCanvas + public static LTDescr LeanAlpha(this CanvasGroup canvas, float to, float time) { return LeanTween.alphaCanvas(canvas, to, time); } + //LeanTween.alphaText + public static LTDescr LeanAlphaText(this RectTransform rectTransform, float to, float time) { return LeanTween.alphaText(rectTransform, to, time); } + //LeanTween.cancel + public static void LeanCancel(this GameObject gameObject) { LeanTween.cancel(gameObject); } + public static void LeanCancel(this GameObject gameObject, bool callOnComplete) { LeanTween.cancel(gameObject, callOnComplete); } + public static void LeanCancel(this GameObject gameObject, int uniqueId, bool callOnComplete = false) { LeanTween.cancel(gameObject, uniqueId, callOnComplete); } + //LeanTween.cancel + public static void LeanCancel(this RectTransform rectTransform) { LeanTween.cancel(rectTransform); } + //LeanTween.cancelAll + //LeanTween.color + public static LTDescr LeanColor(this GameObject gameObject, Color to, float time) { return LeanTween.color(gameObject, to, time); } + //LeanTween.colorText + public static LTDescr LeanColorText(this RectTransform rectTransform, Color to, float time) { return LeanTween.colorText(rectTransform, to, time); } + //LeanTween.delayedCall + public static LTDescr LeanDelayedCall(this GameObject gameObject, float delayTime, System.Action callback) { return LeanTween.delayedCall(gameObject, delayTime, callback); } + public static LTDescr LeanDelayedCall(this GameObject gameObject, float delayTime, System.Action callback) { return LeanTween.delayedCall(gameObject, delayTime, callback); } + + //LeanTween.isPaused + public static bool LeanIsPaused(this GameObject gameObject) { return LeanTween.isPaused(gameObject); } + public static bool LeanIsPaused(this RectTransform rectTransform) { return LeanTween.isPaused(rectTransform); } + + //LeanTween.isTweening + public static bool LeanIsTweening(this GameObject gameObject) { return LeanTween.isTweening(gameObject); } + //LeanTween.isTweening + //LeanTween.move + public static LTDescr LeanMove(this GameObject gameObject, Vector3 to, float time) { return LeanTween.move(gameObject, to, time); } + public static LTDescr LeanMove(this Transform transform, Vector3 to, float time) { return LeanTween.move(transform.gameObject, to, time); } + public static LTDescr LeanMove(this RectTransform rectTransform, Vector3 to, float time) { return LeanTween.move(rectTransform, to, time); } + //LeanTween.move + public static LTDescr LeanMove(this GameObject gameObject, Vector2 to, float time) { return LeanTween.move(gameObject, to, time); } + public static LTDescr LeanMove(this Transform transform, Vector2 to, float time) { return LeanTween.move(transform.gameObject, to, time); } + //LeanTween.move + public static LTDescr LeanMove(this GameObject gameObject, Vector3[] to, float time) { return LeanTween.move(gameObject, to, time); } + public static LTDescr LeanMove(this GameObject gameObject, LTBezierPath to, float time) { return LeanTween.move(gameObject, to, time); } + public static LTDescr LeanMove(this GameObject gameObject, LTSpline to, float time) { return LeanTween.move(gameObject, to, time); } + public static LTDescr LeanMove(this Transform transform, Vector3[] to, float time) { return LeanTween.move(transform.gameObject, to, time); } + public static LTDescr LeanMove(this Transform transform, LTBezierPath to, float time) { return LeanTween.move(transform.gameObject, to, time); } + public static LTDescr LeanMove(this Transform transform, LTSpline to, float time) { return LeanTween.move(transform.gameObject, to, time); } + //LeanTween.moveLocal + public static LTDescr LeanMoveLocal(this GameObject gameObject, Vector3 to, float time) { return LeanTween.moveLocal(gameObject, to, time); } + public static LTDescr LeanMoveLocal(this GameObject gameObject, LTBezierPath to, float time) { return LeanTween.moveLocal(gameObject, to, time); } + public static LTDescr LeanMoveLocal(this GameObject gameObject, LTSpline to, float time) { return LeanTween.moveLocal(gameObject, to, time); } + public static LTDescr LeanMoveLocal(this Transform transform, Vector3 to, float time) { return LeanTween.moveLocal(transform.gameObject, to, time); } + public static LTDescr LeanMoveLocal(this Transform transform, LTBezierPath to, float time) { return LeanTween.moveLocal(transform.gameObject, to, time); } + public static LTDescr LeanMoveLocal(this Transform transform, LTSpline to, float time) { return LeanTween.moveLocal(transform.gameObject, to, time); } + //LeanTween.moveLocal + public static LTDescr LeanMoveLocalX(this GameObject gameObject, float to, float time) { return LeanTween.moveLocalX(gameObject, to, time); } + public static LTDescr LeanMoveLocalY(this GameObject gameObject, float to, float time) { return LeanTween.moveLocalY(gameObject, to, time); } + public static LTDescr LeanMoveLocalZ(this GameObject gameObject, float to, float time) { return LeanTween.moveLocalZ(gameObject, to, time); } + public static LTDescr LeanMoveLocalX(this Transform transform, float to, float time) { return LeanTween.moveLocalX(transform.gameObject, to, time); } + public static LTDescr LeanMoveLocalY(this Transform transform, float to, float time) { return LeanTween.moveLocalY(transform.gameObject, to, time); } + public static LTDescr LeanMoveLocalZ(this Transform transform, float to, float time) { return LeanTween.moveLocalZ(transform.gameObject, to, time); } + //LeanTween.moveSpline + public static LTDescr LeanMoveSpline(this GameObject gameObject, Vector3[] to, float time) { return LeanTween.moveSpline(gameObject, to, time); } + public static LTDescr LeanMoveSpline(this GameObject gameObject, LTSpline to, float time) { return LeanTween.moveSpline(gameObject, to, time); } + public static LTDescr LeanMoveSpline(this Transform transform, Vector3[] to, float time) { return LeanTween.moveSpline(transform.gameObject, to, time); } + public static LTDescr LeanMoveSpline(this Transform transform, LTSpline to, float time) { return LeanTween.moveSpline(transform.gameObject, to, time); } + //LeanTween.moveSplineLocal + public static LTDescr LeanMoveSplineLocal(this GameObject gameObject, Vector3[] to, float time) { return LeanTween.moveSplineLocal(gameObject, to, time); } + public static LTDescr LeanMoveSplineLocal(this Transform transform, Vector3[] to, float time) { return LeanTween.moveSplineLocal(transform.gameObject, to, time); } + //LeanTween.moveX + public static LTDescr LeanMoveX(this GameObject gameObject, float to, float time) { return LeanTween.moveX(gameObject, to, time); } + public static LTDescr LeanMoveX(this Transform transform, float to, float time) { return LeanTween.moveX(transform.gameObject, to, time); } + //LeanTween.moveX (RectTransform) + public static LTDescr LeanMoveX(this RectTransform rectTransform, float to, float time) { return LeanTween.moveX(rectTransform, to, time); } + //LeanTween.moveY + public static LTDescr LeanMoveY(this GameObject gameObject, float to, float time) { return LeanTween.moveY(gameObject, to, time); } + public static LTDescr LeanMoveY(this Transform transform, float to, float time) { return LeanTween.moveY(transform.gameObject, to, time); } + //LeanTween.moveY (RectTransform) + public static LTDescr LeanMoveY(this RectTransform rectTransform, float to, float time) { return LeanTween.moveY(rectTransform, to, time); } + //LeanTween.moveZ + public static LTDescr LeanMoveZ(this GameObject gameObject, float to, float time) { return LeanTween.moveZ(gameObject, to, time); } + public static LTDescr LeanMoveZ(this Transform transform, float to, float time) { return LeanTween.moveZ(transform.gameObject, to, time); } + //LeanTween.moveZ (RectTransform) + public static LTDescr LeanMoveZ(this RectTransform rectTransform, float to, float time) { return LeanTween.moveZ(rectTransform, to, time); } + //LeanTween.pause + public static void LeanPause(this GameObject gameObject) { LeanTween.pause(gameObject); } + //LeanTween.play + public static LTDescr LeanPlay(this RectTransform rectTransform, UnityEngine.Sprite[] sprites) { return LeanTween.play(rectTransform, sprites); } + //LeanTween.removeListener + //LeanTween.resume + public static void LeanResume(this GameObject gameObject) { LeanTween.resume(gameObject); } + //LeanTween.resumeAll + //LeanTween.rotate + public static LTDescr LeanRotate(this GameObject gameObject, Vector3 to, float time) { return LeanTween.rotate(gameObject, to, time); } + public static LTDescr LeanRotate(this Transform transform, Vector3 to, float time) { return LeanTween.rotate(transform.gameObject, to, time); } + //LeanTween.rotate + //LeanTween.rotate (RectTransform) + public static LTDescr LeanRotate(this RectTransform rectTransform, Vector3 to, float time) { return LeanTween.rotate(rectTransform, to, time); } + //LeanTween.rotateAround + public static LTDescr LeanRotateAround(this GameObject gameObject, Vector3 axis, float add, float time) { return LeanTween.rotateAround(gameObject, axis, add, time); } + public static LTDescr LeanRotateAround(this Transform transform, Vector3 axis, float add, float time) { return LeanTween.rotateAround(transform.gameObject, axis, add, time); } + //LeanTween.rotateAround (RectTransform) + public static LTDescr LeanRotateAround(this RectTransform rectTransform, Vector3 axis, float add, float time) { return LeanTween.rotateAround(rectTransform, axis, add, time); } + //LeanTween.rotateAroundLocal + public static LTDescr LeanRotateAroundLocal(this GameObject gameObject, Vector3 axis, float add, float time) { return LeanTween.rotateAroundLocal(gameObject, axis, add, time); } + public static LTDescr LeanRotateAroundLocal(this Transform transform, Vector3 axis, float add, float time) { return LeanTween.rotateAroundLocal(transform.gameObject, axis, add, time); } + //LeanTween.rotateAround (RectTransform) + public static LTDescr LeanRotateAroundLocal(this RectTransform rectTransform, Vector3 axis, float add, float time) { return LeanTween.rotateAroundLocal(rectTransform, axis, add, time); } + //LeanTween.rotateLocal + //LeanTween.rotateX + public static LTDescr LeanRotateX(this GameObject gameObject, float to, float time) { return LeanTween.rotateX(gameObject, to, time); } + public static LTDescr LeanRotateX(this Transform transform, float to, float time) { return LeanTween.rotateX(transform.gameObject, to, time); } + //LeanTween.rotateY + public static LTDescr LeanRotateY(this GameObject gameObject, float to, float time) { return LeanTween.rotateY(gameObject, to, time); } + public static LTDescr LeanRotateY(this Transform transform, float to, float time) { return LeanTween.rotateY(transform.gameObject, to, time); } + //LeanTween.rotateZ + public static LTDescr LeanRotateZ(this GameObject gameObject, float to, float time) { return LeanTween.rotateZ(gameObject, to, time); } + public static LTDescr LeanRotateZ(this Transform transform, float to, float time) { return LeanTween.rotateZ(transform.gameObject, to, time); } + //LeanTween.scale + public static LTDescr LeanScale(this GameObject gameObject, Vector3 to, float time) { return LeanTween.scale(gameObject, to, time); } + public static LTDescr LeanScale(this Transform transform, Vector3 to, float time) { return LeanTween.scale(transform.gameObject, to, time); } + //LeanTween.scale (GUI) + //LeanTween.scale (RectTransform) + public static LTDescr LeanScale(this RectTransform rectTransform, Vector3 to, float time) { return LeanTween.scale(rectTransform, to, time); } + //LeanTween.scaleX + public static LTDescr LeanScaleX(this GameObject gameObject, float to, float time) { return LeanTween.scaleX(gameObject, to, time); } + public static LTDescr LeanScaleX(this Transform transform, float to, float time) { return LeanTween.scaleX(transform.gameObject, to, time); } + //LeanTween.scaleY + public static LTDescr LeanScaleY(this GameObject gameObject, float to, float time) { return LeanTween.scaleY(gameObject, to, time); } + public static LTDescr LeanScaleY(this Transform transform, float to, float time) { return LeanTween.scaleY(transform.gameObject, to, time); } + //LeanTween.scaleZ + public static LTDescr LeanScaleZ(this GameObject gameObject, float to, float time) { return LeanTween.scaleZ(gameObject, to, time); } + public static LTDescr LeanScaleZ(this Transform transform, float to, float time) { return LeanTween.scaleZ(transform.gameObject, to, time); } + //LeanTween.sequence + //LeanTween.size (RectTransform) + public static LTDescr LeanSize(this RectTransform rectTransform, Vector2 to, float time) { return LeanTween.size(rectTransform, to, time); } + //LeanTween.tweensRunning + //LeanTween.value (Color) + public static LTDescr LeanValue(this GameObject gameObject, Color from, Color to, float time) { return LeanTween.value(gameObject, from, to, time); } + //LeanTween.value (Color) + //LeanTween.value (float) + public static LTDescr LeanValue(this GameObject gameObject, float from, float to, float time) { return LeanTween.value(gameObject, from, to, time); } + public static LTDescr LeanValue(this GameObject gameObject, Vector2 from, Vector2 to, float time) { return LeanTween.value(gameObject, from, to, time); } + public static LTDescr LeanValue(this GameObject gameObject, Vector3 from, Vector3 to, float time) { return LeanTween.value(gameObject, from, to, time); } + //LeanTween.value (float) + public static LTDescr LeanValue(this GameObject gameObject, Action callOnUpdate, float from, float to, float time) { return LeanTween.value(gameObject, callOnUpdate, from, to, time); } + public static LTDescr LeanValue(this GameObject gameObject, Action callOnUpdate, float from, float to, float time) { return LeanTween.value(gameObject, callOnUpdate, from, to, time); } + public static LTDescr LeanValue(this GameObject gameObject, Action callOnUpdate, float from, float to, float time) { return LeanTween.value(gameObject, callOnUpdate, from, to, time); } + public static LTDescr LeanValue(this GameObject gameObject, Action callOnUpdate, Color from, Color to, float time) { return LeanTween.value(gameObject, callOnUpdate, from, to, time); } + public static LTDescr LeanValue(this GameObject gameObject, Action callOnUpdate, Vector2 from, Vector2 to, float time) { return LeanTween.value(gameObject, callOnUpdate, from, to, time); } + public static LTDescr LeanValue(this GameObject gameObject, Action callOnUpdate, Vector3 from, Vector3 to, float time) { return LeanTween.value(gameObject, callOnUpdate, from, to, time); } + + public static void LeanSetPosX(this Transform transform, float val) + { + transform.position = new Vector3(val, transform.position.y, transform.position.z); + } + public static void LeanSetPosY(this Transform transform, float val) + { + transform.position = new Vector3(transform.position.x, val, transform.position.z); + } + public static void LeanSetPosZ(this Transform transform, float val) + { + transform.position = new Vector3(transform.position.x, transform.position.y, val); + } + + public static void LeanSetLocalPosX(this Transform transform, float val) + { + transform.localPosition = new Vector3(val, transform.localPosition.y, transform.localPosition.z); + } + public static void LeanSetLocalPosY(this Transform transform, float val) + { + transform.localPosition = new Vector3(transform.localPosition.x, val, transform.localPosition.z); + } + public static void LeanSetLocalPosZ(this Transform transform, float val) + { + transform.localPosition = new Vector3(transform.localPosition.x, transform.localPosition.y, val); + } + + public static Color LeanColor(this Transform transform) + { + return transform.GetComponent().material.color; + } +} diff --git a/KFAttached/LeanTween/Framework/LeanTweenExt.cs.meta b/KFAttached/LeanTween/Framework/LeanTweenExt.cs.meta new file mode 100644 index 0000000..2283703 --- /dev/null +++ b/KFAttached/LeanTween/Framework/LeanTweenExt.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5dbe851e9c0814f1d8f514ecf70f675d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/LeanTween/License.txt b/KFAttached/LeanTween/License.txt new file mode 100644 index 0000000..4f43b9a --- /dev/null +++ b/KFAttached/LeanTween/License.txt @@ -0,0 +1,31 @@ +The MIT License (MIT) + +Copyright (c) 2017 Russell Savage - Dented Pixel + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +TERMS OF USE - EASING EQUATIONS +Open source under the BSD License. +Copyright (c)2001 Robert Penner +All rights reserved. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/KFAttached/LeanTween/License.txt.meta b/KFAttached/LeanTween/License.txt.meta new file mode 100644 index 0000000..b10e33d --- /dev/null +++ b/KFAttached/LeanTween/License.txt.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: e389e9bcd4f944c338327697bd209cad +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Misc.meta b/KFAttached/Misc.meta new file mode 100644 index 0000000..d8ab251 --- /dev/null +++ b/KFAttached/Misc.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e90139dce980d4840bf4b20c1114b015 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Misc/AimReference.cs b/KFAttached/Misc/AimReference.cs new file mode 100644 index 0000000..d4789d0 --- /dev/null +++ b/KFAttached/Misc/AimReference.cs @@ -0,0 +1,49 @@ +using System; +using UnityEngine; + +public class AimReference : MonoBehaviour +{ + [NonSerialized] + public Vector3 positionOffset; + [NonSerialized] + public Quaternion rotationOffset; + [NonSerialized] + public AimReferenceGroup group; + [NonSerialized] + public int index = -1; + [NonSerialized] + public ScopeBase scopeBase; + [SerializeField] + private GameObject scopeBindingObject; + public bool asReference; + + private void OnEnable() + { + if (!group) + { + return; + } + scopeBase = GetComponentInParent(); + Transform refTrans = scopeBase ? scopeBase.transform : transform.parent; + rotationOffset = Quaternion.Inverse(refTrans.rotation) * transform.rotation; + positionOffset = refTrans.InverseTransformDirection(transform.position - refTrans.position); + group.UpdateEnableStates(); + } + + private void OnDisable() + { + if (!group) + { + return; + } + group.UpdateEnableStates(); + } + + public void UpdateEnableState(bool state) + { + if (scopeBindingObject) + { + scopeBindingObject.SetActive(state); + } + } +} \ No newline at end of file diff --git a/KFAttached/Misc/AimReference.cs.meta b/KFAttached/Misc/AimReference.cs.meta new file mode 100644 index 0000000..b7cd99c --- /dev/null +++ b/KFAttached/Misc/AimReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 53a21d5a88ab0034c8b0db6ea40e7d85 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Misc/AimReferenceGroup.cs b/KFAttached/Misc/AimReferenceGroup.cs new file mode 100644 index 0000000..1433bd9 --- /dev/null +++ b/KFAttached/Misc/AimReferenceGroup.cs @@ -0,0 +1,62 @@ +#if NotEditor +using KFCommonUtilityLib; +#endif +using UnityEngine; + +public class AimReferenceGroup : MonoBehaviour +{ + [SerializeField] + public AimReference[] aimReferences; + private bool registered; + +#if NotEditor + private ActionModuleProceduralAiming.ProceduralAimingData data; + private void Awake() + { + if (aimReferences != null) + { + foreach (var reference in aimReferences) + { + reference.group = this; + } + } + + EntityPlayerLocal player = GetComponentInParent(); + if (aimReferences == null || aimReferences.Length == 0 || !player || player.inventory?.holdingItemData?.actionData?[1] is not IModuleContainerFor module) + { + Destroy(this); + if (aimReferences != null) + { + foreach (var reference in aimReferences) + { + Destroy(reference); + } + aimReferences = null; + } + return; + } + data = module.Instance; + } + + private void OnEnable() + { + if (registered) + { + return; + } + registered = data.RegisterGroup(aimReferences, gameObject.name); + } +#endif + + internal void UpdateEnableStates() + { +#if NotEditor + if (!registered) + { + return; + } + data.UpdateCurrentReference(); +#endif + } +} + diff --git a/KFAttached/Misc/AimReferenceGroup.cs.meta b/KFAttached/Misc/AimReferenceGroup.cs.meta new file mode 100644 index 0000000..468e69f --- /dev/null +++ b/KFAttached/Misc/AimReferenceGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 93cdda222d3f0e24aa2b48c9b9fd7b81 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Misc/AttachmentReference.cs b/KFAttached/Misc/AttachmentReference.cs new file mode 100644 index 0000000..0564261 --- /dev/null +++ b/KFAttached/Misc/AttachmentReference.cs @@ -0,0 +1,7 @@ +using UnityEngine; + +[AddComponentMenu("")] +public class AttachmentReference : MonoBehaviour +{ + public Transform attachmentReference; +} \ No newline at end of file diff --git a/KFAttached/Misc/AttachmentReference.cs.meta b/KFAttached/Misc/AttachmentReference.cs.meta new file mode 100644 index 0000000..13024ae --- /dev/null +++ b/KFAttached/Misc/AttachmentReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3ade2782c6b27f6448984f3d9d0ef550 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Misc/AttachmentReferenceAppended.cs b/KFAttached/Misc/AttachmentReferenceAppended.cs new file mode 100644 index 0000000..990602b --- /dev/null +++ b/KFAttached/Misc/AttachmentReferenceAppended.cs @@ -0,0 +1,45 @@ +using UnityEngine; + +public class AttachmentReferenceAppended : AttachmentReference +{ + private Transform[] bindings; + public void Merge(AnimationTargetsAbs targets) + { + if (attachmentReference && targets) + { + foreach (var bindings in attachmentReference.GetComponentsInChildren(true)) + { + bindings.targets = targets; + } + bindings = new Transform[attachmentReference.childCount]; + for (int i = 0; i < attachmentReference.childCount; i++) + { + bindings[i] = attachmentReference.GetChild(i); + bindings[i].SetParent(targets.AttachmentRef, false); + } + Destroy(attachmentReference.gameObject); + attachmentReference = null; + } + } + + public void Remove() + { + if (bindings != null) + { + foreach (var binding in bindings) + { + if (binding) + { + binding.SetParent(null, false); + Destroy(binding.gameObject); + } + } + bindings = null; + } + if (attachmentReference) + { + Destroy(attachmentReference.gameObject); + attachmentReference = null; + } + } +} \ No newline at end of file diff --git a/KFAttached/Misc/AttachmentReferenceAppended.cs.meta b/KFAttached/Misc/AttachmentReferenceAppended.cs.meta new file mode 100644 index 0000000..fc84559 --- /dev/null +++ b/KFAttached/Misc/AttachmentReferenceAppended.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f2f4680216a56a6479d51c0c8a9f51a5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Misc/AudioSourceGroup.cs b/KFAttached/Misc/AudioSourceGroup.cs new file mode 100644 index 0000000..9b4c7b4 --- /dev/null +++ b/KFAttached/Misc/AudioSourceGroup.cs @@ -0,0 +1,15 @@ +using System; +using UnityEngine; + +[Serializable] +public class AudioSourceGroup +{ + [SerializeField] + public string groupName; + [SerializeField] + public AudioClip[] clips = new AudioClip[0]; + [SerializeField] + public AudioSource source; + + public bool IsValid => source != null && clips != null && clips.Length > 0 && source != null; +} diff --git a/KFAttached/Misc/AudioSourceGroup.cs.meta b/KFAttached/Misc/AudioSourceGroup.cs.meta new file mode 100644 index 0000000..dc394f5 --- /dev/null +++ b/KFAttached/Misc/AudioSourceGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c8d5d39385ea6d348b03c7cdf161c572 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Misc/IgnoreTint.cs b/KFAttached/Misc/IgnoreTint.cs new file mode 100644 index 0000000..6055923 --- /dev/null +++ b/KFAttached/Misc/IgnoreTint.cs @@ -0,0 +1,6 @@ +using UnityEngine; + +public class IgnoreTint : MonoBehaviour +{ + +} \ No newline at end of file diff --git a/KFAttached/Misc/IgnoreTint.cs.meta b/KFAttached/Misc/IgnoreTint.cs.meta new file mode 100644 index 0000000..3b7e42c --- /dev/null +++ b/KFAttached/Misc/IgnoreTint.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 122c053de47e8a14aa2aa57287456e86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Misc/ItemAnimatorUpdate.cs b/KFAttached/Misc/ItemAnimatorUpdate.cs new file mode 100644 index 0000000..4c03668 --- /dev/null +++ b/KFAttached/Misc/ItemAnimatorUpdate.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using UnityEngine.Animations.Rigging; +using UnityEngine.Playables; + +[AddComponentMenu("")] +[DisallowMultipleComponent] +internal class ItemAnimatorUpdate : MonoBehaviour +{ + private Animator animator; + private RigBuilder weaponRB; + internal PlayableGraph graph; + + private void Awake() + { + animator = GetComponent(); + TryGetComponent(out weaponRB); + } + + private void Update() + { + //animator.playableGraph.Evaluate(Time.deltaTime); + animator.Update(Time.deltaTime); + //graph.Evaluate(Time.deltaTime); + //weaponRB?.Evaluate(Time.deltaTime); + } +} \ No newline at end of file diff --git a/KFAttached/Misc/ItemAnimatorUpdate.cs.meta b/KFAttached/Misc/ItemAnimatorUpdate.cs.meta new file mode 100644 index 0000000..54307c3 --- /dev/null +++ b/KFAttached/Misc/ItemAnimatorUpdate.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8b9545ce69a57b542aef2de6d8093b73 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Misc/PlayerRigLateUpdate.cs b/KFAttached/Misc/PlayerRigLateUpdate.cs new file mode 100644 index 0000000..db2ee45 --- /dev/null +++ b/KFAttached/Misc/PlayerRigLateUpdate.cs @@ -0,0 +1,34 @@ +using System; +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[Obsolete] +[AddComponentMenu("")] +public class PlayerRigLateUpdate : MonoBehaviour +{ +#if NotEditor + //private Animator animator; + //private RigBuilder rigBuilder; + //private void Awake() + //{ + // animator = GetComponent(); + // rigBuilder = GetComponent(); + //} + + //private void OnAnimatorMove() + //{ + // if (rigBuilder.enabled) + // ForceToManualUpdate(); + //} + + //private void LateUpdate() + //{ + // rigBuilder.Evaluate(Time.deltaTime); + //} + + //private void ForceToManualUpdate() + //{ + // RigTargets.RebuildRig(animator, rigBuilder); + //} +#endif +} diff --git a/KFAttached/Misc/PlayerRigLateUpdate.cs.meta b/KFAttached/Misc/PlayerRigLateUpdate.cs.meta new file mode 100644 index 0000000..ec2c2dc --- /dev/null +++ b/KFAttached/Misc/PlayerRigLateUpdate.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f95fdfaecc53e6146a222aa23dd93ae2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Misc/ScopeBase.cs b/KFAttached/Misc/ScopeBase.cs new file mode 100644 index 0000000..b8d26a0 --- /dev/null +++ b/KFAttached/Misc/ScopeBase.cs @@ -0,0 +1,5 @@ +using UnityEngine; + +public class ScopeBase : MonoBehaviour +{ +} \ No newline at end of file diff --git a/KFAttached/Misc/ScopeBase.cs.meta b/KFAttached/Misc/ScopeBase.cs.meta new file mode 100644 index 0000000..b05c636 --- /dev/null +++ b/KFAttached/Misc/ScopeBase.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 22006be69eab7844e8873de3daedd07c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Misc/WeaponCameraFollow.cs b/KFAttached/Misc/WeaponCameraFollow.cs new file mode 100644 index 0000000..9c56384 --- /dev/null +++ b/KFAttached/Misc/WeaponCameraFollow.cs @@ -0,0 +1,62 @@ +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.PostProcessing; + +[AddComponentMenu("")] +public class WeaponCameraFollow : MonoBehaviour +{ + public RenderTexture targetTexture; +#if NotEditor + public ActionModuleDynamicSensitivity.DynamicSensitivityData dynamicSensitivityData; + public EntityPlayerLocal player; +#endif + + private void OnEnable() + { +#if NotEditor + OcclusionManager.Instance.SetMultipleCameras(true); + if (dynamicSensitivityData != null) + { + dynamicSensitivityData.activated = true; + } + //UpdateAntialiasing(); +#endif + } + + private void OnDisable() + { +#if NotEditor + OcclusionManager.Instance.SetMultipleCameras(false); + if (dynamicSensitivityData != null) + { + dynamicSensitivityData.activated = false; + } +#endif + if (!targetTexture || !targetTexture.IsCreated()) + { + return; + } + var cmd = new CommandBuffer(); + cmd.SetRenderTarget(targetTexture); + cmd.ClearRenderTarget(true, true, Color.black); + Graphics.ExecuteCommandBuffer(cmd); + cmd.Dispose(); + } + +#if NotEditor + public void UpdateAntialiasing() + { + var pipCamera = GetComponent(); + var layer = GetComponent(); + var prevFsr = player.renderManager.fsr; + int num = player.renderManager.dlssEnabled ? 0 : GamePrefs.GetInt(EnumGamePrefs.OptionsGfxAA); + float @float = GamePrefs.GetFloat(EnumGamePrefs.OptionsGfxAASharpness); + player.renderManager.FSRInit(layer.superResolution); + player.renderManager.SetAntialiasing(num, @float, layer); + Rect rect = pipCamera.rect; + rect.x = ((layer.antialiasingMode == PostProcessLayer.Antialiasing.SuperResolution) ? 1E-07f : 0f); + pipCamera.rect = rect; + player.renderManager.fsr = prevFsr; + } +#endif +} diff --git a/KFAttached/Misc/WeaponCameraFollow.cs.meta b/KFAttached/Misc/WeaponCameraFollow.cs.meta new file mode 100644 index 0000000..44e623e --- /dev/null +++ b/KFAttached/Misc/WeaponCameraFollow.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b9ea69da20db0064282418fbfd9a57c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Render.meta b/KFAttached/Render.meta new file mode 100644 index 0000000..e9febb3 --- /dev/null +++ b/KFAttached/Render.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e92eb85b5d313f248a46263f550fcc0f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Render/BokehBlurTargetRef.cs b/KFAttached/Render/BokehBlurTargetRef.cs new file mode 100644 index 0000000..ac2b51d --- /dev/null +++ b/KFAttached/Render/BokehBlurTargetRef.cs @@ -0,0 +1,12 @@ +using UnityEngine; + +namespace KFCommonUtilityLib.KFAttached.Render +{ + [AddComponentMenu("")] + public class BokehBlurTargetRef : MonoBehaviour + { +#if NotEditor + internal MagnifyScope target; +#endif + } +} diff --git a/KFAttached/Render/BokehBlurTargetRef.cs.meta b/KFAttached/Render/BokehBlurTargetRef.cs.meta new file mode 100644 index 0000000..0c73ea8 --- /dev/null +++ b/KFAttached/Render/BokehBlurTargetRef.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 16ae170c638bd434dbe48e1b9e46ac99 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Render/MagnifyScope.cs b/KFAttached/Render/MagnifyScope.cs new file mode 100644 index 0000000..245fe1c --- /dev/null +++ b/KFAttached/Render/MagnifyScope.cs @@ -0,0 +1,405 @@ +#if NotEditor +using HarmonyLib; +using System; +using System.Reflection; +#endif +using UnityEngine; +using UnityEngine.Rendering.PostProcessing; + +namespace KFCommonUtilityLib.KFAttached.Render +{ + [AddComponentMenu("KFAttachments/Render Utils/Magnify Scope")] + [RequireComponent(typeof(Renderer))] + public class MagnifyScope : MonoBehaviour + { +#if NotEditor + private static Shader newShader; + private static FieldInfo fieldResources = AccessTools.Field(typeof(PostProcessLayer), "m_Resources"); +#endif + private RenderTexture targetTexture; + private Renderer renderTarget; + + private Camera pipCamera; + [Header("Core")] + [SerializeField] + private bool manualControl = false; + [SerializeField] + private Transform cameraJoint; + [SerializeField] + private float aspectRatio = 1.0f; + [SerializeField] + private bool hideFpvModelInScope = false; + [SerializeField] + private bool variableZoom = false; + [Header("Reticle Scaling")] + [SerializeField] + private bool scaleReticle = false; + [SerializeField] + private Vector2 reticleSizeRange = new Vector2(1, 1); + //[SerializeField] + //private bool scaleDownReticle = false; + //[SerializeField] + //private float reticleScaleRatio = 1.0f; + [Header("Camera Texture Size And Procedural Aiming")] + [SerializeField] + private Transform aimRef; + [SerializeField] + private float lensSizeFull; + [SerializeField] + private float lensSizeValid; + + private float initialReticleScale = 1f; + private float initialFov = 55f; + private float textureHeight = Screen.height; + +#if NotEditor + private EntityPlayerLocal player; + private int itemSlot = -1; + private ItemActionZoom.ItemActionDataZoom zoomActionData; + private bool IsVariableZoom => variableZoom && variableZoomData != null; + private ActionModuleVariableZoom.VariableZoomData variableZoomData; + private float targetStep = 0; + private float currentStep = 0; + private float stepVelocity = 0; +#else + [Header("Editor Debug")] + public Camera debugCamera; + public float debugScale = 2f; +#endif + private void Awake() + { + renderTarget = GetComponent(); + if (!renderTarget) + { + Destroy(this); + return; + } +#if NotEditor + + if (newShader == null) + { + newShader = LoadManager.LoadAsset("#@modfolder(CommonUtilityLib):Resources/PIPScope.unity3d?PIPScope.shadergraph", null, null, false, true).Asset; + } + if (renderTarget.material.shader.name == "Shader Graphs/MagnifyScope" || renderTarget.material.shader.name == "Shader Graphs/PIPScopeNew") + { + renderTarget.material.shader = newShader; + } + initialReticleScale = renderTarget.material.GetFloat("_ReticleScale"); +#else + if(debugCamera == null) + { + Destroy(this); + return; + } +#endif + //if (!player.playerCamera.TryGetComponent(out var bokeh)) + //{ + // bokeh = player.playerCamera.gameObject.AddComponent(); + //} + //bokeh.target = this; + // Precompute rotations + } + +#if NotEditor + private void Start() + { + var entity = GetComponentInParent(); + if (!entity) + { + Destroy(gameObject); + return; + } + player = entity; + itemSlot = player.inventory.holdingItemIdx; + OnEnable(); + } +#endif + + private void OnEnable() + { + float targetFov; +#if NotEditor + if (!player) + { + return; + } + CalcInitialFov(); + //inventory holding item is not set when creating model, this might be an issue for items with base scope that has this script attached + //workaround taken from alternative action module, which keeps a reference to the ItemValue being set until its custom data is created + //afterwards it's set to null so we still need to access holding item when this method is triggered by mods + if (itemSlot != player.inventory.holdingItemIdx) + { + Log.Out($"Scope shader script: Expecting holding item idx {itemSlot} but getting {player.inventory.holdingItemIdx}!"); + return; + } + var zoomAction = (ItemActionZoom)((ActionModuleAlternative.InventorySetItemTemp?.ItemClass ?? player.inventory.holdingItem).Actions[1]); + zoomActionData = (ItemActionZoom.ItemActionDataZoom)player.inventory.holdingItemData.actionData[1]; + variableZoomData = (zoomActionData as IModuleContainerFor)?.Instance; + if (variableZoomData != null && (variableZoom || variableZoomData.forceFov)) + { + if (variableZoom) + { + variableZoomData.shouldUpdate = false; + targetStep = currentStep = variableZoomData.curStep; + stepVelocity = 0f; + targetFov = CalcCurrentFov(); + } + else + { + targetFov = variableZoomData.fovRange.min; + } + } + else + { + string originalRatio = zoomAction.Properties.GetString("ZoomRatio"); + if (string.IsNullOrEmpty(originalRatio)) + { + originalRatio = "0"; + } + targetFov = StringParsers.ParseFloat(player.inventory.holdingItemItemValue.GetPropertyOverride("ZoomRatio", originalRatio)); + targetFov = ScaleToFov(targetFov); + } + +#else + if(debugCamera == null) + { + Destroy(this); + } + targetFov = Mathf.Rad2Deg * 2 * Mathf.Atan(Mathf.Tan(Mathf.Deg2Rad * 27.5f) / Mathf.Sqrt(debugScale)); +#endif + CreateCamera(); + UpdateFOV(targetFov); + } + +#if NotEditor + private void Update() + { + if (IsVariableZoom) + { + if (variableZoomData.shouldUpdate) + { + variableZoomData.shouldUpdate = false; + targetStep = variableZoomData.curStep; + } + if (currentStep != targetStep) + { + if (variableZoomData.isToggleOnly) + { + currentStep = targetStep; + } + else + { + currentStep = Mathf.SmoothDamp(currentStep, targetStep, ref stepVelocity, 0.05f); + } + UpdateFOV(CalcCurrentFov()); + } + } + + if (!manualControl && zoomActionData != null) + { + if (player.bFirstPersonView) + { + bool aimingGun = player.AimingGun; + if (aimingGun && !pipCamera.gameObject.activeSelf) + { + pipCamera.gameObject.SetActive(true); + } + else if (!aimingGun && !zoomActionData.bZoomInProgress && pipCamera.gameObject.activeSelf) + { + pipCamera.gameObject.SetActive(false); + } + } + else if (pipCamera.gameObject.activeSelf) + { + pipCamera.gameObject.SetActive(false); + } + } + } +#endif + + private void OnDisable() + { + DestroyCamera(); +#if NotEditor + currentStep = targetStep = stepVelocity = 0f; +#else + if(debugCamera == null) + { + Destroy(this); + } +#endif + } + + private float ScaleToFov(float scale) + { + return Mathf.Rad2Deg * 2 * Mathf.Atan(Mathf.Tan(Mathf.Deg2Rad * initialFov * 0.5f) / scale); + } + + private float FovToScale(float fov) + { + return Mathf.Tan(Mathf.Deg2Rad * initialFov * 0.5f) / Mathf.Tan(Mathf.Deg2Rad * fov * 0.5f); + } + +#if NotEditor + private void CalcInitialFov() + { + if (aimRef) + { + var distance = Mathf.Abs(Vector3.Dot(renderTarget.bounds.center - aimRef.position, aimRef.forward)); + var scaleFov = lensSizeValid / (2 * distance * Mathf.Tan(Mathf.Deg2Rad * 27.5f)); + var scaleTexture = lensSizeFull / (2 * distance * Mathf.Tan(Mathf.Deg2Rad * 27.5f)); + textureHeight = scaleTexture * Screen.height; + //textureHeight = Mathf.Abs(player.playerCamera.WorldToScreenPoint(player.playerCamera.transform.forward * distance + player.playerCamera.transform.up * height).y - + // player.playerCamera.WorldToScreenPoint(player.playerCamera.transform.forward * distance - player.playerCamera.transform.up * height).y); + initialFov = Mathf.Rad2Deg * 2 * Mathf.Atan(Mathf.Tan(Mathf.Deg2Rad * 27.5f) * scaleFov); + Log.Out($"distance {distance}, scale fov {scaleFov}, scale texture {scaleTexture} texture height {textureHeight} initial fov {initialFov}"); + return; + } + textureHeight = Screen.height * 0.5f; + initialFov = 15; + } + + private static float CalcFovStep(float t, float fovMin, float fovMax) + { + return 2f * Mathf.Rad2Deg * Mathf.Atan(Mathf.Lerp(Mathf.Tan(fovMax * 0.5f * Mathf.Deg2Rad), Mathf.Tan(fovMin * 0.5f * Mathf.Deg2Rad), t)); + } + + private float CalcCurrentFov() + { + if (!IsVariableZoom) + { + throw new Exception("Variable Zoom is not set!"); + } + float targetFov; + if (variableZoomData.forceFov) + { + targetFov = CalcFovStep(currentStep, variableZoomData.fovRange.min, variableZoomData.fovRange.max); + } + else + { + targetFov = ScaleToFov(Mathf.Lerp(variableZoomData.minScale, variableZoomData.maxScale, currentStep)); + } + return targetFov; + } +#endif + + private void DestroyCamera() + { + if (targetTexture && targetTexture.IsCreated()) + { + targetTexture.Release(); + Destroy(targetTexture); + } + if (pipCamera) + { + Destroy(pipCamera.gameObject); + } + } + + private void UpdateFOV(float targetFov) + { + if (targetFov > 0) + { + pipCamera.fieldOfView = targetFov; +#if NotEditor + if (scaleReticle && IsVariableZoom) + { + renderTarget.material.SetFloat("_ReticleScale", Mathf.Lerp(reticleSizeRange.x, reticleSizeRange.y, currentStep)); + //if (variableZoomData.maxScale > variableZoomData.minScale) + //{ + // float minScale; + // if (reticleScaleRatio >= 1) + // { + // minScale = scaleDownReticle ? 1 - (variableZoomData.maxScale * reticleScaleRatio - variableZoomData.minScale) / (variableZoomData.maxScale * reticleScaleRatio) : 1; + // } + // else + // { + // minScale = scaleDownReticle ? 1 - reticleScaleRatio * (variableZoomData.maxScale - variableZoomData.minScale) / variableZoomData.maxScale : 1; + // } + // float maxScale; + // if (reticleScaleRatio >= 1) + // { + // maxScale = scaleDownReticle ? 1 : variableZoomData.maxScale * reticleScaleRatio / variableZoomData.minScale; + // } + // else + // { + // maxScale = scaleDownReticle ? 1 : 1 + reticleScaleRatio * (variableZoomData.maxScale - variableZoomData.minScale) / variableZoomData.minScale; + // } + // float reticleScale = Mathf.Lerp(minScale, maxScale, variableZoomData.curStep); + // renderTarget.material.SetFloat("_ReticleScale", initialReticleScale / reticleScale); + //} + //else + //{ + // renderTarget.material.SetFloat("_ReticleScale", initialReticleScale); + //} + } + //Log.Out($"target fov {targetFov} target scale {targetScale}"); +#endif + } + } + + private void CreateCamera() + { + const float texScale = 1f; + targetTexture = new RenderTexture((int)(textureHeight * aspectRatio), (int)(textureHeight), 24, RenderTextureFormat.ARGBHalf, RenderTextureReadWrite.Linear) + { + filterMode = FilterMode.Bilinear, + wrapMode = TextureWrapMode.Clamp + }; + renderTarget.material.mainTexture = targetTexture; + GameObject cameraGO = new GameObject("KFPiPCam"); + if (cameraJoint != null) + { + cameraGO.transform.parent = cameraJoint.transform; + } + else + { + cameraGO.transform.parent = transform; + } + + pipCamera = cameraGO.AddComponent(); + pipCamera.targetTexture = targetTexture; + pipCamera.depth = -2; + pipCamera.fieldOfView = 55; + pipCamera.nearClipPlane = 0.05f; + pipCamera.farClipPlane = 5000; + pipCamera.aspect = aspectRatio; + pipCamera.rect = new Rect(0, 0, texScale, texScale); +#if NotEditor + //pipCamera.CopyFrom(player.playerCamera); + pipCamera.cullingMask = player.playerCamera.cullingMask; + //renderTarget.material.SetFloat("_AspectMain", player.playerCamera.aspect); + //renderTarget.material.SetFloat("_AspectScope", pipCamera.aspect); +#else + pipCamera.CopyFrom(debugCamera); +#endif + if (cameraJoint == null || hideFpvModelInScope) + { + pipCamera.cullingMask &= ~(1024); + } + else + { + pipCamera.cullingMask |= 1024; + } + cameraGO.transform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); + cameraGO.transform.localScale = Vector3.one; + +#if NotEditor + WeaponCameraFollow weaponCameraFollow = cameraGO.AddComponent(); + weaponCameraFollow.targetTexture = targetTexture; + weaponCameraFollow.dynamicSensitivityData = (zoomActionData as IModuleContainerFor)?.Instance; + weaponCameraFollow.player = player; + var old = player.playerCamera.GetComponent(); + var layer = pipCamera.gameObject.GetOrAddComponent(); + //layer.antialiasingMode = old.antialiasingMode; + //layer.superResolution = (SuperResolution)old.superResolution.GetType().CreateInstance(); + layer.Init(fieldResources.GetValue(old) as PostProcessResources); + //weaponCameraFollow.UpdateAntialiasing(); +#endif + } + + internal void RenderImageCallback(RenderTexture source, RenderTexture destination) + { + } + } +} diff --git a/KFAttached/Render/MagnifyScope.cs.meta b/KFAttached/Render/MagnifyScope.cs.meta new file mode 100644 index 0000000..b4968bd --- /dev/null +++ b/KFAttached/Render/MagnifyScope.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 54496e2804e57d84da57d0241db8bdf6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/Render/MagnifyScopeTargetRef.cs b/KFAttached/Render/MagnifyScopeTargetRef.cs new file mode 100644 index 0000000..cd2450e --- /dev/null +++ b/KFAttached/Render/MagnifyScopeTargetRef.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace KFCommonUtilityLib.KFAttached.Render +{ + [AddComponentMenu("")] + internal class MagnifyScopeTargetRef : MonoBehaviour + { + private HashSet targets = new HashSet(); + + private void OnRenderImage(RenderTexture source, RenderTexture destination) + { + foreach (var target in targets) + { + target.RenderImageCallback(source, destination); + } + Graphics.Blit(source, destination); + } + + internal void AddTarget(MagnifyScope target) + { + if (targets.Count == 0) + { + enabled = true; + } + targets.Add(target); + } + + internal void RemoveTarget(MagnifyScope target) + { + targets.Remove(target); + if(targets.Count == 0 ) + { + enabled = false; + } + } + } +} diff --git a/KFAttached/Render/MagnifyScopeTargetRef.cs.meta b/KFAttached/Render/MagnifyScopeTargetRef.cs.meta new file mode 100644 index 0000000..fececde --- /dev/null +++ b/KFAttached/Render/MagnifyScopeTargetRef.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b65f1de3a5df39443a8af191b067c5d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors.meta b/KFAttached/RigAdaptors.meta new file mode 100644 index 0000000..bed2421 --- /dev/null +++ b/KFAttached/RigAdaptors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3fabd6babec972349939cbd377f41ba1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors.meta b/KFAttached/RigAdaptors/Adaptors.meta new file mode 100644 index 0000000..40fb700 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cecc0dfc3c12e4f4dab5bbe3f4ba7c1d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/BlendConstraintAdaptor.cs b/KFAttached/RigAdaptors/Adaptors/BlendConstraintAdaptor.cs new file mode 100644 index 0000000..1d04bfb --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/BlendConstraintAdaptor.cs @@ -0,0 +1,56 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class BlendConstraintAdaptor : RigAdaptorAbs +{ + [SerializeField] + private string m_ConstrainedObject; + [SerializeField] + private Transform m_SourceA; + [SerializeField] + private Transform m_SourceB; + [SerializeField] + private bool m_BlendPosition; + [SerializeField] + private bool m_BlendRotation; + [SerializeField] + private float m_PositionWeight; + [SerializeField] + private float m_RotationWeight; + [SerializeField] + private bool m_MaintainPositionOffsets; + [SerializeField] + private bool m_MaintainRotationOffsets; + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject?.name; + m_SourceA = constraint.data.sourceObjectA; + m_SourceB = constraint.data.sourceObjectB; + m_BlendPosition = constraint.data.blendPosition; + m_BlendRotation = constraint.data.blendRotation; + m_PositionWeight = constraint.data.positionWeight; + m_RotationWeight = constraint.data.rotationWeight; + m_MaintainPositionOffsets = constraint.data.maintainPositionOffsets; + m_MaintainRotationOffsets = constraint.data.maintainRotationOffsets; + } + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.constrainedObject = targetRoot.FindInAllChildren(m_ConstrainedObject); + constraint.data.sourceObjectA = m_SourceA; + constraint.data.sourceObjectB = m_SourceB; + constraint.data.blendPosition = m_BlendPosition; + constraint.data.blendRotation = m_BlendRotation; + constraint.data.positionWeight = m_PositionWeight; + constraint.data.rotationWeight = m_RotationWeight; + constraint.data.maintainPositionOffsets = m_MaintainPositionOffsets; + constraint.data.maintainRotationOffsets = m_MaintainRotationOffsets; + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/BlendConstraintAdaptor.cs.meta b/KFAttached/RigAdaptors/Adaptors/BlendConstraintAdaptor.cs.meta new file mode 100644 index 0000000..be3d6df --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/BlendConstraintAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b2ca56f5a0b464646817033fcff9f693 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/ChainIKConstraintAdaptor.cs b/KFAttached/RigAdaptors/Adaptors/ChainIKConstraintAdaptor.cs new file mode 100644 index 0000000..286a69a --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/ChainIKConstraintAdaptor.cs @@ -0,0 +1,56 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class ChainIKConstraintAdaptor : RigAdaptorAbs +{ + [SerializeField] + private string m_Root; + [SerializeField] + private string m_Tip; + [SerializeField] + private Transform m_Target; + [SerializeField] + private float m_ChainRotationWeight; + [SerializeField] + private float m_TipRotationWeight; + [SerializeField] + private int m_MaxIterations; + [SerializeField] + private float m_Tolerance; + [SerializeField] + private bool m_MaintainTargetPositionOffset; + [SerializeField] + private bool m_MaintainTargetRotationOffset; + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_Root = constraint.data.root?.name; + m_Tip = constraint.data.tip?.name; + m_Target = constraint.data.target; + m_ChainRotationWeight = constraint.data.chainRotationWeight; + m_TipRotationWeight = constraint.data.tipRotationWeight; + m_MaxIterations = constraint.data.maxIterations; + m_Tolerance = constraint.data.tolerance; + m_MaintainTargetPositionOffset = constraint.data.maintainTargetPositionOffset; + m_MaintainTargetRotationOffset = constraint.data.maintainTargetRotationOffset; + } + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.root = targetRoot.FindInAllChildren(m_Root); + constraint.data.tip = targetRoot.FindInAllChildren(m_Tip); + constraint.data.target = m_Target; + constraint.data.chainRotationWeight = m_ChainRotationWeight; + constraint.data.tipRotationWeight = m_TipRotationWeight; + constraint.data.maxIterations = m_MaxIterations; + constraint.data.tolerance = m_Tolerance; + constraint.data.maintainTargetPositionOffset = m_MaintainTargetPositionOffset; + constraint.data.maintainTargetRotationOffset = m_MaintainTargetRotationOffset; + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/ChainIKConstraintAdaptor.cs.meta b/KFAttached/RigAdaptors/Adaptors/ChainIKConstraintAdaptor.cs.meta new file mode 100644 index 0000000..40211d1 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/ChainIKConstraintAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b4dd415747e268478ef7e27093e78a4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/DampedTransformAdaptor.cs b/KFAttached/RigAdaptors/Adaptors/DampedTransformAdaptor.cs new file mode 100644 index 0000000..2fa5f47 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/DampedTransformAdaptor.cs @@ -0,0 +1,38 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class DampedTransformAdaptor : RigAdaptorAbs +{ + [SerializeField] + private string m_ConstrainedObject; + [SerializeField] + private Transform m_Source; + [SerializeField] + private float m_DampPosition; + [SerializeField] + private float m_DampRotation; + [SerializeField] + private bool m_MaintainAim; + public override void FindRigTargets() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject?.name; + m_Source = constraint.data.sourceObject; + m_DampPosition = constraint.data.dampPosition; + m_DampRotation = constraint.data.dampRotation; + m_MaintainAim = constraint.data.maintainAim; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + constraint.weight = weight; + constraint.data.constrainedObject = targetRoot.FindInAllChildren(m_ConstrainedObject); + constraint.data.sourceObject = m_Source; + constraint.data.dampPosition = m_DampPosition; + constraint.data.dampRotation = m_DampRotation; + constraint.data.maintainAim = m_MaintainAim; + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/DampedTransformAdaptor.cs.meta b/KFAttached/RigAdaptors/Adaptors/DampedTransformAdaptor.cs.meta new file mode 100644 index 0000000..44d505e --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/DampedTransformAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7eae293f02f20ea4e83de9504d5a5f93 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/Data.meta b/KFAttached/RigAdaptors/Adaptors/Data.meta new file mode 100644 index 0000000..45662ed --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/Data.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 28f7c996c8fc946498369133083c03d9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/Data/TwistNode.cs b/KFAttached/RigAdaptors/Adaptors/Data/TwistNode.cs new file mode 100644 index 0000000..9e798e9 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/Data/TwistNode.cs @@ -0,0 +1,22 @@ +using System; +using UnityEngine; + +namespace KFCommonUtilityLib.RigAdaptors.Adaptors.Data +{ + [Serializable] + public class TwistNode + { + [SerializeField] + public string name; + [SerializeField] + public float weight; + + public TwistNode() { } + + public TwistNode(string name, float weight) + { + this.name = name; + this.weight = weight; + } + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/Data/TwistNode.cs.meta b/KFAttached/RigAdaptors/Adaptors/Data/TwistNode.cs.meta new file mode 100644 index 0000000..6f59232 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/Data/TwistNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ce4dc6aaaa5e6564d8f5975388620f86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/MultiAimConstraintAdaptor.cs b/KFAttached/RigAdaptors/Adaptors/MultiAimConstraintAdaptor.cs new file mode 100644 index 0000000..0eacca8 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/MultiAimConstraintAdaptor.cs @@ -0,0 +1,68 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class MultiAimConstraintAdaptor : RigAdaptorAbs +{ + [SerializeField] + private string m_ConstrainedObject; + [SerializeField] + private WeightedTransformArray m_SourceObjects; + [SerializeField] + private Vector3 m_Offset; + [SerializeField] + private Vector2 m_limits; + [SerializeField] + private MultiAimConstraintData.Axis m_AimAxis; + [SerializeField] + private MultiAimConstraintData.Axis m_UpAxis; + [SerializeField] + private MultiAimConstraintData.WorldUpType m_WorldUpType; + [SerializeField] + private string m_WorldUpObject; + [SerializeField] + private MultiAimConstraintData.Axis m_WorldUpAxis; + [SerializeField] + private bool m_MaintainOffset; + [SerializeField] + private Vector3Bool m_ConstrainedAxes; + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.constrainedObject = targetRoot.FindInAllChildren(m_ConstrainedObject); + constraint.data.sourceObjects = m_SourceObjects; + constraint.data.offset = m_Offset; + constraint.data.limits = m_limits; + constraint.data.aimAxis = m_AimAxis; + constraint.data.upAxis = m_UpAxis; + constraint.data.worldUpType = m_WorldUpType; + if (!string.IsNullOrEmpty(m_WorldUpObject)) + constraint.data.worldUpObject = targetRoot.FindInAllChildren(m_WorldUpObject); + constraint.data.worldUpAxis = m_WorldUpAxis; + constraint.data.maintainOffset = m_MaintainOffset; + constraint.data.constrainedXAxis = m_ConstrainedAxes.x; + constraint.data.constrainedYAxis = m_ConstrainedAxes.y; + constraint.data.constrainedZAxis = m_ConstrainedAxes.z; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject?.name; + m_SourceObjects = constraint.data.sourceObjects; + m_Offset = constraint.data.offset; + m_limits = constraint.data.limits; + m_AimAxis = constraint.data.aimAxis; + m_UpAxis = constraint.data.upAxis; + m_WorldUpType = constraint.data.worldUpType; + if ((m_WorldUpType == MultiAimConstraintData.WorldUpType.ObjectUp || m_WorldUpType == MultiAimConstraintData.WorldUpType.ObjectRotationUp) && constraint.data.worldUpObject) + m_WorldUpObject = constraint.data.worldUpObject.name; + m_WorldUpAxis = constraint.data.worldUpAxis; + m_MaintainOffset = constraint.data.maintainOffset; + m_ConstrainedAxes = new Vector3Bool(constraint.data.constrainedXAxis, constraint.data.constrainedYAxis, constraint.data.constrainedZAxis); + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/MultiAimConstraintAdaptor.cs.meta b/KFAttached/RigAdaptors/Adaptors/MultiAimConstraintAdaptor.cs.meta new file mode 100644 index 0000000..36bedcc --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/MultiAimConstraintAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 80b6e2441c0c1ab46a65e9ff120057de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/MultiParentConstraintAdaptor.cs b/KFAttached/RigAdaptors/Adaptors/MultiParentConstraintAdaptor.cs new file mode 100644 index 0000000..6531c31 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/MultiParentConstraintAdaptor.cs @@ -0,0 +1,47 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class MultiParentConstraintAdaptor : RigAdaptorAbs +{ + [SerializeField] + private string m_ConstrainedObject; + [SerializeField] + private WeightedTransformArray m_SourceObjects; + [SerializeField] + private Vector3Bool m_ConstrainedPositionAxes; + [SerializeField] + private Vector3Bool m_ConstrainedRotationAxes; + [SerializeField] + private bool m_MaintainPositionOffset; + [SerializeField] + private bool m_MaintainRotationOffset; + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.constrainedObject = targetRoot.FindInAllChildren(m_ConstrainedObject); + constraint.data.sourceObjects = m_SourceObjects; + constraint.data.constrainedPositionXAxis = m_ConstrainedPositionAxes.x; + constraint.data.constrainedPositionYAxis = m_ConstrainedPositionAxes.y; + constraint.data.constrainedPositionZAxis = m_ConstrainedPositionAxes.z; + constraint.data.constrainedRotationXAxis = m_ConstrainedRotationAxes.x; + constraint.data.constrainedRotationYAxis = m_ConstrainedRotationAxes.y; + constraint.data.constrainedRotationZAxis = m_ConstrainedRotationAxes.z; + constraint.data.maintainPositionOffset = m_MaintainPositionOffset; + constraint.data.maintainRotationOffset = m_MaintainRotationOffset; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject?.name; + m_SourceObjects = constraint.data.sourceObjects; + m_ConstrainedPositionAxes = new Vector3Bool(constraint.data.constrainedPositionXAxis, constraint.data.constrainedPositionYAxis, constraint.data.constrainedPositionZAxis); + m_ConstrainedRotationAxes = new Vector3Bool(constraint.data.constrainedRotationXAxis, constraint.data.constrainedRotationYAxis, constraint.data.constrainedRotationZAxis); + m_MaintainPositionOffset = constraint.data.maintainPositionOffset; + m_MaintainRotationOffset = constraint.data.maintainRotationOffset; + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/MultiParentConstraintAdaptor.cs.meta b/KFAttached/RigAdaptors/Adaptors/MultiParentConstraintAdaptor.cs.meta new file mode 100644 index 0000000..9a209ff --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/MultiParentConstraintAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1efc37cc0b8c5d748832a228eef2373c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/MultiPositionConstraintAdaptor.cs b/KFAttached/RigAdaptors/Adaptors/MultiPositionConstraintAdaptor.cs new file mode 100644 index 0000000..3a9d50c --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/MultiPositionConstraintAdaptor.cs @@ -0,0 +1,42 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class MultiPositionConstraintAdaptor : RigAdaptorAbs +{ + [SerializeField] + private string m_ConstrainedObject; + [SerializeField] + private WeightedTransformArray m_SourceObjects; + [SerializeField] + private Vector3 m_Offset; + [SerializeField] + private Vector3Bool m_ConstrainedAxes; + [SerializeField] + private bool m_MaintainOffset; + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.constrainedObject = targetRoot.FindInAllChildren(m_ConstrainedObject); + constraint.data.sourceObjects = m_SourceObjects; + constraint.data.offset = m_Offset; + constraint.data.constrainedXAxis = m_ConstrainedAxes.x; + constraint.data.constrainedYAxis = m_ConstrainedAxes.y; + constraint.data.constrainedZAxis = m_ConstrainedAxes.z; + constraint.data.maintainOffset = m_MaintainOffset; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject?.name; + m_SourceObjects = constraint.data.sourceObjects; + m_Offset = constraint.data.offset; + m_ConstrainedAxes = new Vector3Bool(constraint.data.constrainedXAxis, constraint.data.constrainedYAxis, constraint.data.constrainedZAxis); + m_MaintainOffset = constraint.data.maintainOffset; + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/MultiPositionConstraintAdaptor.cs.meta b/KFAttached/RigAdaptors/Adaptors/MultiPositionConstraintAdaptor.cs.meta new file mode 100644 index 0000000..69c4636 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/MultiPositionConstraintAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d705cece31c4abd4495c5fdf8203afe5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/MultiReferentialConstraintAdaptor.cs b/KFAttached/RigAdaptors/Adaptors/MultiReferentialConstraintAdaptor.cs new file mode 100644 index 0000000..072fd7c --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/MultiReferentialConstraintAdaptor.cs @@ -0,0 +1,29 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class MultiReferentialConstraintAdaptor : RigAdaptorAbs +{ + [SerializeField] + private int m_Driver; + [SerializeField] + private List m_SourceObjects; + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.driver = m_Driver; + constraint.data.sourceObjects = m_SourceObjects; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_Driver = constraint.data.driver; + m_SourceObjects = constraint.data.sourceObjects; + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/MultiReferentialConstraintAdaptor.cs.meta b/KFAttached/RigAdaptors/Adaptors/MultiReferentialConstraintAdaptor.cs.meta new file mode 100644 index 0000000..e404446 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/MultiReferentialConstraintAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e103ecfa73363f14a90b16031c25e8b6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/MultiRotationConstraintAdaptor.cs b/KFAttached/RigAdaptors/Adaptors/MultiRotationConstraintAdaptor.cs new file mode 100644 index 0000000..4fbe272 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/MultiRotationConstraintAdaptor.cs @@ -0,0 +1,42 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class MultiRotationConstraintAdaptor : RigAdaptorAbs +{ + [SerializeField] + private string m_ConstrainedObject; + [SerializeField] + private WeightedTransformArray m_SourceObjects; + [SerializeField] + private Vector3 m_Offset; + [SerializeField] + private Vector3Bool m_ConstrainedAxes; + [SerializeField] + private bool m_MaintainOffset; + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.constrainedObject = targetRoot.FindInAllChildren(m_ConstrainedObject); + constraint.data.sourceObjects = m_SourceObjects; + constraint.data.offset = m_Offset; + constraint.data.constrainedXAxis = m_ConstrainedAxes.x; + constraint.data.constrainedYAxis = m_ConstrainedAxes.y; + constraint.data.constrainedZAxis = m_ConstrainedAxes.z; + constraint.data.maintainOffset = m_MaintainOffset; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject?.name; + m_SourceObjects = constraint.data.sourceObjects; + m_Offset = constraint.data.offset; + m_ConstrainedAxes = new Vector3Bool(constraint.data.constrainedXAxis, constraint.data.constrainedYAxis, constraint.data.constrainedZAxis); + m_MaintainOffset = constraint.data.maintainOffset; + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/MultiRotationConstraintAdaptor.cs.meta b/KFAttached/RigAdaptors/Adaptors/MultiRotationConstraintAdaptor.cs.meta new file mode 100644 index 0000000..8a9c356 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/MultiRotationConstraintAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: de8f43467d976b544b7967ab5425d23b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/OverrideTransformAdaptor.cs b/KFAttached/RigAdaptors/Adaptors/OverrideTransformAdaptor.cs new file mode 100644 index 0000000..69179b1 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/OverrideTransformAdaptor.cs @@ -0,0 +1,48 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class OverrideTransformAdaptor : RigAdaptorAbs +{ + [SerializeField] + private string m_ConstrainedObject; + [SerializeField] + private Transform m_OverrideSource; + [SerializeField] + private Vector3 m_OverridePosition; + [SerializeField] + private Vector3 m_OverrideRotation; + [SerializeField] + private float m_PositionWeight; + [SerializeField] + private float m_RotationWeight; + [SerializeField] + private OverrideTransformData.Space m_Space; + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.constrainedObject = targetRoot.FindInAllChildren(m_ConstrainedObject); + constraint.data.sourceObject = m_OverrideSource; + constraint.data.position = m_OverridePosition; + constraint.data.rotation = m_OverrideRotation; + constraint.data.positionWeight = m_PositionWeight; + constraint.data.rotationWeight = m_RotationWeight; + constraint.data.space = m_Space; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject?.name; + m_OverrideSource = constraint.data.sourceObject; + m_OverridePosition = constraint.data.position; + m_OverrideRotation = constraint.data.rotation; + m_PositionWeight = constraint.data.positionWeight; + m_RotationWeight = constraint.data.rotationWeight; + m_Space = constraint.data.space; + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/OverrideTransformAdaptor.cs.meta b/KFAttached/RigAdaptors/Adaptors/OverrideTransformAdaptor.cs.meta new file mode 100644 index 0000000..6aa2c70 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/OverrideTransformAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b059f9f28d4d2e46a30530eeede98a4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/RigAdaptorAbs.cs b/KFAttached/RigAdaptors/Adaptors/RigAdaptorAbs.cs new file mode 100644 index 0000000..85782bf --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/RigAdaptorAbs.cs @@ -0,0 +1,34 @@ +using System; +using UnityEngine; +using UnityEngine.Animations.Rigging; + +public abstract class RigAdaptorAbs : MonoBehaviour +{ + [NonSerialized] + public Transform targetRoot; + [SerializeField] + protected float weight = 1f; + public abstract void ReadRigData(); + public abstract void FindRigTargets(); + + protected void WeightedTransformArrayToAdaptor(WeightedTransformArray array, out string[] transforms, out float[] weights) + { + transforms = new string[array.Count]; + weights = new float[array.Count]; + for (int i = 0; i < array.Count; i++) + { + transforms[i] = array[i].transform?.name; + weights[i] = array[i].weight; + } + } + + protected WeightedTransformArray WeightedTransformArrayFromAdaptor(Transform targetRoot, string[] transforms, float[] weights) + { + WeightedTransformArray array = new WeightedTransformArray(); + for (int i = 0; i < transforms.Length; i++) + { + array.Add(new WeightedTransform(targetRoot.FindInAllChildren(transforms[i]), weights[i])); + } + return array; + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/RigAdaptorAbs.cs.meta b/KFAttached/RigAdaptors/Adaptors/RigAdaptorAbs.cs.meta new file mode 100644 index 0000000..c348e47 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/RigAdaptorAbs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a19d5243587a11344927b47b3a9240fd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/TwistChainConstraintAdaptor.cs b/KFAttached/RigAdaptors/Adaptors/TwistChainConstraintAdaptor.cs new file mode 100644 index 0000000..00e4aa3 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/TwistChainConstraintAdaptor.cs @@ -0,0 +1,40 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class TwistChainConstraintAdaptor : RigAdaptorAbs +{ + [SerializeField] + private string m_Root; + [SerializeField] + private string m_Tip; + [SerializeField] + private Transform m_RootTarget; + [SerializeField] + private Transform m_TipTarget; + [SerializeField] + private AnimationCurve m_Curve; + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.root = targetRoot.FindInAllChildren(m_Root); + constraint.data.tip = targetRoot.FindInAllChildren(m_Tip); + constraint.data.rootTarget = m_RootTarget; + constraint.data.tipTarget = m_TipTarget; + constraint.data.curve = m_Curve; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_Root = constraint.data.root?.name; + m_Tip = constraint.data.tip?.name; + m_RootTarget = constraint.data.rootTarget; + m_TipTarget = constraint.data.tipTarget; + m_Curve = constraint.data.curve; + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/TwistChainConstraintAdaptor.cs.meta b/KFAttached/RigAdaptors/Adaptors/TwistChainConstraintAdaptor.cs.meta new file mode 100644 index 0000000..72b2cd4 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/TwistChainConstraintAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e71b15efb8d89b9428eaee7b14e80f8d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/TwistCorrectionAdaptor.cs b/KFAttached/RigAdaptors/Adaptors/TwistCorrectionAdaptor.cs new file mode 100644 index 0000000..9688006 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/TwistCorrectionAdaptor.cs @@ -0,0 +1,50 @@ +using System.Linq; +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class TwistCorrectionAdaptor : RigAdaptorAbs +{ + [SerializeField] + private string m_Source; + [SerializeField] + private TwistCorrectionData.Axis m_TwistAxis; + [SerializeField] + private string[] m_TwistNodes; + public override void FindRigTargets() + { + var constraint = GetComponent(); + if (m_TwistNodes == null) + { + Log.Error("twist nodes array not serialized!"); + Component.Destroy(constraint); + Component.Destroy(this); + return; + } + constraint.Reset(); + constraint.weight = weight; + constraint.data.sourceObject = targetRoot.FindInAllChildren(m_Source); + constraint.data.twistAxis = m_TwistAxis; + var twistNodes = new WeightedTransformArray(m_TwistNodes.Length); + for (int i = 0; i < m_TwistNodes.Length; i++) + { + string[] node = m_TwistNodes[i].Split(';'); + if (node.Length == 2) + { + if (!string.IsNullOrEmpty(node[0])) + twistNodes.SetTransform(i, targetRoot.FindInAllChildren(node[0])); + twistNodes.SetWeight(i, float.Parse(node[1])); + } + } + constraint.data.twistNodes = twistNodes; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_Source = constraint.data.sourceObject.name; + m_TwistAxis = constraint.data.twistAxis; + m_TwistNodes = constraint.data.twistNodes.Select(n => (n.transform.gameObject?.name ?? "") + ';' + n.weight.ToString()).ToArray(); + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/TwistCorrectionAdaptor.cs.meta b/KFAttached/RigAdaptors/Adaptors/TwistCorrectionAdaptor.cs.meta new file mode 100644 index 0000000..14d38ea --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/TwistCorrectionAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0de395249ff56c646ab5045a6b20568a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Adaptors/TwoBoneIKConstraintAdaptor.cs b/KFAttached/RigAdaptors/Adaptors/TwoBoneIKConstraintAdaptor.cs new file mode 100644 index 0000000..51a9cb2 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/TwoBoneIKConstraintAdaptor.cs @@ -0,0 +1,59 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class TwoBoneIKConstraintAdaptor : RigAdaptorAbs +{ + [SerializeField] + private string m_Root; + [SerializeField] + private string m_Mid; + [SerializeField] + private string m_Tip; + [SerializeField] + private Transform m_Target; + [SerializeField] + private Transform m_Hint; + [SerializeField] + private float m_TargetPositionWeight; + [SerializeField] + private float m_TargetRotationWeight; + [SerializeField] + private float m_HintWeight; + [SerializeField] + private bool m_MaintainTargetPositionOffset; + [SerializeField] + private bool m_MaintainTargetRotationOffset; + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.root = targetRoot.FindInAllChildren(m_Root); + constraint.data.mid = targetRoot.FindInAllChildren(m_Mid); + constraint.data.tip = targetRoot.FindInAllChildren(m_Tip); + constraint.data.target = m_Target; + constraint.data.hint = m_Hint; + constraint.data.targetPositionWeight = m_TargetPositionWeight; + constraint.data.targetRotationWeight = m_TargetRotationWeight; + constraint.data.hintWeight = m_HintWeight; + constraint.data.maintainTargetPositionOffset = m_MaintainTargetPositionOffset; + constraint.data.maintainTargetRotationOffset = m_MaintainTargetRotationOffset; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_Root = constraint.data.root?.name; + m_Mid = constraint.data.mid?.name; + m_Tip = constraint.data.tip?.name; + m_Target = constraint.data.target; + m_Hint = constraint.data.hint; + m_TargetPositionWeight = constraint.data.targetPositionWeight; + m_TargetRotationWeight = constraint.data.targetRotationWeight; + m_HintWeight = constraint.data.hintWeight; + m_MaintainTargetPositionOffset = constraint.data.maintainTargetPositionOffset; + m_MaintainTargetRotationOffset = constraint.data.maintainTargetRotationOffset; + } +} diff --git a/KFAttached/RigAdaptors/Adaptors/TwoBoneIKConstraintAdaptor.cs.meta b/KFAttached/RigAdaptors/Adaptors/TwoBoneIKConstraintAdaptor.cs.meta new file mode 100644 index 0000000..6e81144 --- /dev/null +++ b/KFAttached/RigAdaptors/Adaptors/TwoBoneIKConstraintAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 917124d705d34eb4bb6e982c423de951 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/AnimationTargetsAbs.cs b/KFAttached/RigAdaptors/AnimationTargetsAbs.cs new file mode 100644 index 0000000..e7fa442 --- /dev/null +++ b/KFAttached/RigAdaptors/AnimationTargetsAbs.cs @@ -0,0 +1,542 @@ +#if NotEditor +using KFCommonUtilityLib.Scripts.StaticManagers; +using UniLinq; +#else +using System.Linq; +#endif +using System.Diagnostics; +using UnityEngine; +using UnityEngine.Animations; +using UnityEngine.Animations.Rigging; +using System; +using System.Collections.Generic; + +[AddComponentMenu("")] +public abstract class AnimationTargetsAbs : MonoBehaviour +{ + protected enum ParentName + { + Spine3, + LeftHand, + RightHand, + } + protected static readonly string[] ParentNames = { "Spine3", "LeftHand", "RightHand" }; + protected static string GetParentName(ParentName name) => ParentNames[(int)name]; + [Header("TPV Fields")] + [SerializeField] + protected Transform itemTpv; + [SerializeField] + protected RuntimeAnimatorController weaponRuntimeControllerTpv; + [SerializeField] + protected AvatarMask weaponRigMaskTpv; + [SerializeField] + protected ParentName parentNameTpv; + + private Rig[] rigTpv; + private RigLayer[] rigLayerTpv; + protected Animator itemAnimatorTpv; + protected bool fpvSet = false; + protected bool tpvSet = false; + private Dictionary dict_attachments = new Dictionary(); + + public abstract Transform ItemFpv { get; protected set; } + public abstract Transform AttachmentRef { get; protected set; } + public Transform ItemTpv { get => itemTpv; protected set => itemTpv = value; } + public Transform ItemTpvOrSelf => itemTpv ? itemTpv : transform; + public bool IsFpv { get; set; } + public bool IsAnimationSet => (IsFpv && fpvSet) || (!IsFpv && tpvSet); + public bool Destroyed { get; protected set; } + public Transform PlayerAnimatorTrans { get; private set; } + public Animator ItemAnimator => IsFpv ? ItemAnimatorFpv : ItemAnimatorTpv; + public Transform ItemCurrent => IsFpv ? ItemFpv : ItemTpv; + public Transform ItemCurrentOrDefault => IsFpv ? ItemFpv : ItemTpvOrSelf; + public AnimationGraphBuilder GraphBuilder { get; private set; } + + protected abstract Animator ItemAnimatorFpv { get; } + protected virtual Animator ItemAnimatorTpv => itemAnimatorTpv; + + private Transform spine1, spine2, spine3; + + protected virtual void Awake() + { + foreach (var bindings in GetComponentsInChildren(true)) + { + bindings.targets = this; + } +#if NotEditor + gameObject.GetOrAddComponent().attachmentReference = AttachmentRef; +#endif + if (itemTpv) + { + rigTpv = itemTpv.GetComponentsInChildren(true); +#if NotEditor + if (rigTpv.Length > 0) + { + int uid = TypeBasedUID.UID; + foreach (var rig in rigTpv) + { + rig.gameObject.name += $"_UID_{uid}"; + AnimationRiggingManager.AddRigExcludeName(rig.gameObject.name); + } + } + rigLayerTpv = new RigLayer[rigTpv.Length]; +#endif + itemTpv.gameObject.SetActive(false); + } + } + + //attaching the same prefab multiple times is not allowed! + public void AttachPrefab(GameObject prefab) + { + if (!Destroyed && dict_attachments != null && prefab.TryGetComponent(out var appended)) + { + appended.Merge(this); + dict_attachments[prefab.name] = prefab.gameObject; + } + } + + public GameObject GetPrefab(string name) + { + if (Destroyed || dict_attachments == null || !dict_attachments.TryGetValue(name, out var prefab)) + { + return null; + } + return prefab; + } + + public void Init(Transform playerAnimatorTrans, bool isFpv) + { + if (Destroyed || (isFpv && fpvSet) || (!isFpv && tpvSet)) + { + return; + } + if (!playerAnimatorTrans) + { + Destroy(); + return; + } + var animator = playerAnimatorTrans.GetComponentInChildren(true); + if (!animator) + { + Destroy(); + return; + } + fpvSet = false; + tpvSet = false; + playerAnimatorTrans = animator.transform; + PlayerAnimatorTrans = playerAnimatorTrans; + GraphBuilder = playerAnimatorTrans.AddMissingComponent(); + IsFpv = isFpv; + if (!isFpv) + { + itemAnimatorTpv = animator; + } + else + { + itemAnimatorTpv = null; + } + spine1 = PlayerAnimatorTrans.FindInAllChildren("Spine1"); + spine2 = spine1.Find("Spine2"); + spine3 = spine2.Find("Spine3"); + +#if NotEditor + Utils.SetLayerRecursively(gameObject, 24, Utils.ExcludeLayerZoom); + if (ItemFpv) + { + Utils.SetLayerRecursively(ItemFpv.gameObject, 10, Utils.ExcludeLayerZoom); + } + if (ItemTpv) + { + Utils.SetLayerRecursively(ItemTpv.gameObject, 24, Utils.ExcludeLayerZoom); + } +#endif + if (ItemTpv) + { + ItemTpv.parent = isFpv ? playerAnimatorTrans.parent : playerAnimatorTrans; + ItemTpv.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); + ItemTpv.localScale = Vector3.one; + } + if (!Destroyed) + { + Init(); + SetEnabled(false); + //Log.Out($"Init rig\n{StackTraceUtility.ExtractStackTrace()}"); + } + } + + protected virtual void Init() + { + if (!itemTpv) + { + return; + } + + itemTpv.SetParent(PlayerAnimatorTrans.parent); + itemTpv.position = Vector3.zero; + itemTpv.localPosition = Vector3.zero; + itemTpv.localRotation = Quaternion.identity; + if (!IsFpv) + { + itemAnimatorTpv = PlayerAnimatorTrans.GetComponent(); + if (rigTpv.Length > 0) + { + foreach (var rig in rigTpv) + { + if (rig.TryGetComponent(out var rc)) + { + rc.targetRoot = PlayerAnimatorTrans; + rc.Rebind(); + } + } + } + } + else + { + itemAnimatorTpv = null; + } + } + + public void Setup() + { + if (!PlayerAnimatorTrans) + { + Destroy(); + return; + } + if (IsFpv && ItemFpv && !fpvSet) + { + fpvSet = SetupFpv(); + } + else if (!IsFpv && ItemTpv && !tpvSet) + { + tpvSet = SetupTpv(); + } + } + + protected abstract bool SetupFpv(); + + protected virtual bool SetupTpv() + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + + itemTpv.SetParent(itemAnimatorTpv.transform.FindInAllChildren(GetParentName(parentNameTpv))); + itemTpv.position = Vector3.zero; + itemTpv.localPosition = Vector3.zero; + itemTpv.localRotation = Quaternion.identity; + + GraphBuilder.InitWeapon(ItemTpv, weaponRuntimeControllerTpv, weaponRigMaskTpv); + + var rigBuilder = PlayerAnimatorTrans.AddMissingComponent(); +#if NotEditor + foreach (var layer in rigBuilder.layers) + { + if (layer.name == SDCSUtils.IKRIG) + { + layer.active = false; + } + } +#endif + if (rigTpv.Length > 0) + { + rigBuilder.layers.RemoveAll(r => rigLayerTpv.Any(layer => layer?.name == r.name)); + for (int i = 0; i < rigTpv.Length; i++) + { + rigBuilder.layers.Insert(i, rigLayerTpv[i] = new RigLayer(rigTpv[i], true)); + } + } + BuildRig(PlayerAnimatorTrans.GetComponent(), rigBuilder); + + sw.Stop(); + string info = $"setup tpv animation graph took {sw.ElapsedMilliseconds} ms"; + //info += $"\n{StackTraceUtility.ExtractStackTrace()}"; + Log.Out(info); + return true; + } + + public void Remove() + { + if (!PlayerAnimatorTrans) + { + Destroy(); + return; + } + if (IsFpv && ItemFpv && fpvSet) + { + RemoveFpv(); + fpvSet = false; + } + else if (!IsFpv && ItemTpv && tpvSet) + { + RemoveTpv(); + tpvSet = false; + } + } + + protected abstract void RemoveFpv(); + + protected virtual void RemoveTpv() + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + + itemTpv.SetParent(PlayerAnimatorTrans.parent); + itemTpv.position = Vector3.zero; + itemTpv.localPosition = Vector3.zero; + itemTpv.localRotation = Quaternion.identity; + + var rigBuilder = PlayerAnimatorTrans.AddMissingComponent(); +#if NotEditor + foreach (var layer in rigBuilder.layers) + { + if (layer.name == SDCSUtils.IKRIG) + { + layer.active = true; + } + } +#endif + if (rigTpv.Length > 0) + { + rigBuilder.layers.RemoveAll(r => rigLayerTpv.Any(layer => layer?.name == r.name)); + Array.Clear(rigLayerTpv, 0, rigLayerTpv.Length); + + //rigTpv.transform.SetParent(transform, false); + //rigTpv.gameObject.SetActive(false); + } + BuildRig(PlayerAnimatorTrans.GetComponent(), rigBuilder); + + sw.Stop(); + string info = $"destroy tpv animation graph took {sw.ElapsedMilliseconds} ms"; + //info += $"\n{StackTraceUtility.ExtractStackTrace()}"; + Log.Out(info); + } + + public virtual void Destroy() + { + + if (AttachmentRef) + { + AttachmentRef.parent = transform; + AttachmentRef = null; + } + + DestroyFpv(); + DestroyTpv(); +#if NotEditor + Destroyed = true; +#endif + PlayerAnimatorTrans = null; + dict_attachments = null; + + Component.DestroyImmediate(this); + //Log.Out(StackTraceUtility.ExtractStackTrace()); + } + + public virtual void DestroyFpv() + { + if (ItemFpv) + { + if (IsFpv && fpvSet && PlayerAnimatorTrans) + { + GraphBuilder.SetCurrentTarget(null); + } + ItemFpv.parent = null; + GameObject.DestroyImmediate(ItemFpv.gameObject); + } + fpvSet = false; + ItemFpv = null; + Log.Out("destroy fpv"); + } + + public virtual void DestroyTpv() + { + if (ItemTpv) + { + if (!IsFpv && tpvSet && PlayerAnimatorTrans) + { + GraphBuilder.SetCurrentTarget(null); + } + ItemTpv.parent = null; + GameObject.DestroyImmediate(ItemTpv.gameObject); + } + tpvSet = false; + ItemTpv = null; + Log.Out("destroy tpv"); + } + + public virtual void SetEnabled(bool enabled) + { + if (Destroyed) + { + return; + } + if (AttachmentRef) + { + AttachmentRef.parent = enabled ? (IsFpv ? ItemFpv : ItemTpvOrSelf) : transform; + } + if (enabled) + { + if (ItemFpv) + { + ItemFpv.gameObject.SetActive(IsFpv); + } + if (ItemTpv) + { + ItemTpv.gameObject.SetActive(!IsFpv); + } + Setup(); + } + else + { + Remove(); + if (ItemFpv) + { + ItemFpv.gameObject.SetActive(false); + } + if (ItemTpv) + { + ItemTpv.gameObject.SetActive(false); + } + } + if (ItemTpv) + { + gameObject.SetActive(false); + } + else + { + gameObject.SetActive(!IsFpv); + } + } + + protected void BuildRig(Animator animator, RigBuilder rb) + { + animator.UnbindAllStreamHandles(); + animator.UnbindAllSceneHandles(); + rb.Build(); + animator.Rebind(); + } + + private readonly static int[] resetHashes = new int[] + { + Animator.StringToHash("Reload"), + Animator.StringToHash("PowerAttack"), + Animator.StringToHash("UseItem"), + Animator.StringToHash("ItemUse"), + Animator.StringToHash("WeaponFire") + }; + +#if NotEditor + //VRoid switch view workaround + public void OnEnable() + { + var player = GetComponentInParent(); + if ((player && player.bFirstPersonView) || ItemTpv) + { + gameObject.SetActive(false); + } + } + + public virtual void UpdatePlayerAvatar(AvatarController avatarController, bool rigWeaponChanged) + { + //var itemCurrent = ItemCurrent; + //if (itemCurrent && !itemCurrent.gameObject.activeSelf) + //{ + // Log.Out("Rigged weapon not active, enabling it..."); + // SetEnabled(true); + //} + if (IsAnimationSet) + { + foreach (var hash in resetHashes) + { + var role = GraphBuilder.GetWrapperRoleByParamHash(hash); + if (role == AnimationGraphBuilder.ParamInWrapper.Vanilla || role == AnimationGraphBuilder.ParamInWrapper.Both) + { + GraphBuilder.VanillaWrapper.ResetTrigger(hash); + } + } + } + if (IsFpv && fpvSet) + { + GraphBuilder.VanillaWrapper.Play("idle", 0, 0f); + avatarController.UpdateInt(AvatarController.weaponHoldTypeHash, -1, false); + } + else if (!IsFpv && tpvSet) + { + //avatarController.UpdateInt(AvatarController.weaponHoldTypeHash, 0, false); + //GraphBuilder.VanillaWrapper.Play("Unarmed", GraphBuilder.VanillaWrapper.GetLayerIndex("StandingIdleTurn"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("RightHandHoldPoses"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("RangedRightHandHoldPoses"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("AdditiveOffsetHoldPoses"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("RightArmHoldPoses"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("BothArmsHoldPoses"), 0); + //GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("AdditiveAimPoses"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("UpperBodyAttack"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("BowDrawAndFire"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("UpperBodyUseAndReload"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("AdditiveRangedAttack"), 0); + } + } + + //public void UpdateTpvSpineRotation(EntityPlayer player) + //{ + // if (!IsFpv && tpvSet && player && !player.IsDead()) + // { + // float xOffset = player.rotation.x / 3f; + // float yOffset = 0f; + // if (player.IsCrouching) + // { + // xOffset += 10f; + // yOffset += 5f; + // } + // if (player.MovementState > 0) + // { + // xOffset += player.speedForward; + // } + // if (Time.timeScale > 0.001f) + // { + // spine1.transform.localEulerAngles = new Vector3(spine1.transform.localEulerAngles.x - xOffset, spine1.transform.localEulerAngles.y - yOffset, spine1.transform.localEulerAngles.z); + // spine2.transform.localEulerAngles = new Vector3(spine2.transform.localEulerAngles.x - xOffset, spine2.transform.localEulerAngles.y - yOffset, spine2.transform.localEulerAngles.z); + // spine3.transform.localEulerAngles = new Vector3(spine3.transform.localEulerAngles.x - xOffset, spine3.transform.localEulerAngles.y - yOffset, spine3.transform.localEulerAngles.z); + // return; + // } + // spine1.transform.localEulerAngles = new Vector3(-xOffset, spine1.transform.localEulerAngles.y - yOffset, spine1.transform.localEulerAngles.z); + // spine2.transform.localEulerAngles = new Vector3(-xOffset, spine2.transform.localEulerAngles.y - yOffset, spine2.transform.localEulerAngles.z); + // spine3.transform.localEulerAngles = new Vector3(-xOffset, spine3.transform.localEulerAngles.y - yOffset, spine3.transform.localEulerAngles.z); + // } + //} + +#else + public void Update() + { + if (IsAnimationSet) + { + foreach (var hash in resetHashes) + { + var role = GraphBuilder.GetWrapperRoleByParamHash(hash); + if (role == AnimationGraphBuilder.ParamInWrapper.Vanilla || role == AnimationGraphBuilder.ParamInWrapper.Both) + { + GraphBuilder.VanillaWrapper.ResetTrigger(hash); + } + } + } + if (IsFpv && fpvSet) + { + GraphBuilder.VanillaWrapper.Play("idle", 0, 0f); + } + else if (!IsFpv && tpvSet) + { + //GraphBuilder.VanillaWrapper.Play("Unarmed", GraphBuilder.VanillaWrapper.GetLayerIndex("StandingIdleTurn"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("RightHandHoldPoses"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("RangedRightHandHoldPoses"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("AdditiveOffsetHoldPoses"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("RightArmHoldPoses"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("BothArmsHoldPoses"), 0); + //GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("AdditiveAimPoses"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("UpperBodyAttack"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("BowDrawAndFire"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("UpperBodyUseAndReload"), 0); + GraphBuilder.VanillaWrapper.Play("Empty", GraphBuilder.VanillaWrapper.GetLayerIndex("AdditiveRangedAttack"), 0); + } + } +#endif +} \ No newline at end of file diff --git a/KFAttached/RigAdaptors/AnimationTargetsAbs.cs.meta b/KFAttached/RigAdaptors/AnimationTargetsAbs.cs.meta new file mode 100644 index 0000000..d10dc98 --- /dev/null +++ b/KFAttached/RigAdaptors/AnimationTargetsAbs.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9257aed4b0cc243458e5209dd3fb523d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/PlayGraphTargets.cs b/KFAttached/RigAdaptors/PlayGraphTargets.cs new file mode 100644 index 0000000..03bd0d2 --- /dev/null +++ b/KFAttached/RigAdaptors/PlayGraphTargets.cs @@ -0,0 +1,165 @@ +#if NotEditor +using KFCommonUtilityLib.Scripts.StaticManagers; +using UniLinq; +#else +using System.Linq; +#endif +using System.Diagnostics; +using UnityEngine; +using UnityEngine.Animations.Rigging; +using System; + +[AddComponentMenu("KFAttachments/RigAdaptors/PlayGraph Targets")] +public class PlayGraphTargets : AnimationTargetsAbs +{ + [Header("FPV Fields")] + [SerializeField] + public Transform itemFpv; + [SerializeField] + public Transform attachmentReference; + [SerializeField] + private RuntimeAnimatorController weaponRuntimeControllerFpv; + [SerializeField] + private ParentName parentNameFpv; + + private Rig[] rigFpv; + private RigLayer[] rigLayerFpv; + private Animator itemAnimatorFpv; + public override Transform ItemFpv { get => itemFpv; protected set => itemFpv = value; } + + public override Transform AttachmentRef { get => attachmentReference; protected set => attachmentReference = value; } + + protected override Animator ItemAnimatorFpv => itemAnimatorFpv; + + protected override void Awake() + { + base.Awake(); + if (!itemFpv) + { + return; + } + + rigFpv = itemFpv.GetComponentsInChildren(); +#if NotEditor + if (rigFpv.Length > 0) + { + int uid = TypeBasedUID.UID; + foreach (var rig in rigFpv) + { + rig.gameObject.name += $"_UID_{uid}"; + AnimationRiggingManager.AddRigExcludeName(rig.gameObject.name); + } + } + rigLayerFpv = new RigLayer[rigFpv.Length]; +#endif + itemFpv.gameObject.SetActive(false); + } + + protected override void Init() + { + base.Init(); + if (!itemFpv) + { + return; + } + + itemFpv.SetParent(PlayerAnimatorTrans.parent); + itemFpv.position = Vector3.zero; + itemFpv.localPosition = Vector3.zero; + itemFpv.localRotation = Quaternion.identity; + + if (IsFpv) + { + itemAnimatorFpv = PlayerAnimatorTrans.GetComponent(); + if (rigFpv.Length > 0) + { + foreach (var rig in rigFpv) + { + if (rig.TryGetComponent(out var rc)) + { + rc.targetRoot = PlayerAnimatorTrans; + rc.Rebind(); + } + } + } + } + else + { + itemAnimatorFpv = null; + } + } + + protected override bool SetupFpv() + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + + itemFpv.SetParent(itemAnimatorFpv.transform.FindInAllChildren(GetParentName(parentNameFpv))); + itemFpv.position = Vector3.zero; + itemFpv.localPosition = Vector3.zero; + itemFpv.localRotation = Quaternion.identity; + + GraphBuilder.InitWeapon(itemFpv, weaponRuntimeControllerFpv, null); + var rigBuilder = PlayerAnimatorTrans.AddMissingComponent(); +#if NotEditor + foreach (var layer in rigBuilder.layers) + { + if (layer.name == SDCSUtils.IKRIG) + { + layer.active = false; + } + } +#endif + if (rigFpv.Length > 0) + { + rigBuilder.layers.RemoveAll(r => rigLayerFpv.Any(layer => layer?.name == r.name)); + for (int i = 0; i < rigFpv.Length; i++) + { + rigBuilder.layers.Insert(i, rigLayerFpv[i] = new RigLayer(rigFpv[i], true)); + } + } + BuildRig(PlayerAnimatorTrans.GetComponent(), rigBuilder); + + sw.Stop(); + string info = $"setup fpv animation graph took {sw.ElapsedMilliseconds} ms"; + //info += $"\n{StackTraceUtility.ExtractStackTrace()}"; + Log.Out(info); + return true; + } + + protected override void RemoveFpv() + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + + itemFpv.SetParent(PlayerAnimatorTrans.parent); + itemFpv.position = Vector3.zero; + itemFpv.localPosition = Vector3.zero; + itemFpv.localRotation = Quaternion.identity; + + var rigBuilder = PlayerAnimatorTrans.AddMissingComponent(); +#if NotEditor + foreach (var layer in rigBuilder.layers) + { + if (layer.name == SDCSUtils.IKRIG) + { + layer.active = true; + } + } +#endif + if (rigFpv.Length > 0) + { + rigBuilder.layers.RemoveAll(r => rigLayerFpv.Any(layer => layer?.name == r.name)); + Array.Clear(rigLayerFpv, 0, rigLayerFpv.Length); + + //rigFpv.transform.SetParent(transform, false); + //rigFpv.gameObject.SetActive(false); + } + BuildRig(PlayerAnimatorTrans.GetComponent(), rigBuilder); + + sw.Stop(); + string info = $"destroy fpv animation graph took {sw.ElapsedMilliseconds} ms"; + //info += $"\n{StackTraceUtility.ExtractStackTrace()}"; + Log.Out(info); + } +} \ No newline at end of file diff --git a/KFAttached/RigAdaptors/PlayGraphTargets.cs.meta b/KFAttached/RigAdaptors/PlayGraphTargets.cs.meta new file mode 100644 index 0000000..ce559c4 --- /dev/null +++ b/KFAttached/RigAdaptors/PlayGraphTargets.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6cdb3ae68f5838c49a4ee601f977eb76 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors.meta b/KFAttached/RigAdaptors/ReverseAdaptors.meta new file mode 100644 index 0000000..c958550 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8c37be1fa2e9bdc4eae9a203d5cf95c4 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/BlendConstraintReverseAdaptor.cs b/KFAttached/RigAdaptors/ReverseAdaptors/BlendConstraintReverseAdaptor.cs new file mode 100644 index 0000000..9384a6b --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/BlendConstraintReverseAdaptor.cs @@ -0,0 +1,56 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class BlendConstraintReverseAdaptor : RigAdaptorAbs +{ + [SerializeField] + private Transform m_ConstrainedObject; + [SerializeField] + private string m_SourceA; + [SerializeField] + private string m_SourceB; + [SerializeField] + private bool m_BlendPosition; + [SerializeField] + private bool m_BlendRotation; + [SerializeField] + private float m_PositionWeight; + [SerializeField] + private float m_RotationWeight; + [SerializeField] + private bool m_MaintainPositionOffsets; + [SerializeField] + private bool m_MaintainRotationOffsets; + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject; + m_SourceA = constraint.data.sourceObjectA?.name; + m_SourceB = constraint.data.sourceObjectB?.name; + m_BlendPosition = constraint.data.blendPosition; + m_BlendRotation = constraint.data.blendRotation; + m_PositionWeight = constraint.data.positionWeight; + m_RotationWeight = constraint.data.rotationWeight; + m_MaintainPositionOffsets = constraint.data.maintainPositionOffsets; + m_MaintainRotationOffsets = constraint.data.maintainRotationOffsets; + } + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.constrainedObject = m_ConstrainedObject; + constraint.data.sourceObjectA = targetRoot.FindInAllChildren(m_SourceA); + constraint.data.sourceObjectB = targetRoot.FindInAllChildren(m_SourceB); + constraint.data.blendPosition = m_BlendPosition; + constraint.data.blendRotation = m_BlendRotation; + constraint.data.positionWeight = m_PositionWeight; + constraint.data.rotationWeight = m_RotationWeight; + constraint.data.maintainPositionOffsets = m_MaintainPositionOffsets; + constraint.data.maintainRotationOffsets = m_MaintainRotationOffsets; + } +} diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/BlendConstraintReverseAdaptor.cs.meta b/KFAttached/RigAdaptors/ReverseAdaptors/BlendConstraintReverseAdaptor.cs.meta new file mode 100644 index 0000000..2bdfff3 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/BlendConstraintReverseAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 98945ef0fc0d660459661507c533176e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/ChainIKConstraintReverseAdaptor.cs b/KFAttached/RigAdaptors/ReverseAdaptors/ChainIKConstraintReverseAdaptor.cs new file mode 100644 index 0000000..d9f138d --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/ChainIKConstraintReverseAdaptor.cs @@ -0,0 +1,56 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class ChainIKConstraintReverseAdaptor : RigAdaptorAbs +{ + [SerializeField] + private Transform m_Root; + [SerializeField] + private Transform m_Tip; + [SerializeField] + private string m_Target; + [SerializeField] + private float m_ChainRotationWeight; + [SerializeField] + private float m_TipRotationWeight; + [SerializeField] + private int m_MaxIterations; + [SerializeField] + private float m_Tolerance; + [SerializeField] + private bool m_MaintainTargetPositionOffset; + [SerializeField] + private bool m_MaintainTargetRotationOffset; + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_Root = constraint.data.root; + m_Tip = constraint.data.tip; + m_Target = constraint.data.target?.name; + m_ChainRotationWeight = constraint.data.chainRotationWeight; + m_TipRotationWeight = constraint.data.tipRotationWeight; + m_MaxIterations = constraint.data.maxIterations; + m_Tolerance = constraint.data.tolerance; + m_MaintainTargetPositionOffset = constraint.data.maintainTargetPositionOffset; + m_MaintainTargetRotationOffset = constraint.data.maintainTargetRotationOffset; + } + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.root = m_Root; + constraint.data.tip = m_Tip; + constraint.data.target = targetRoot.FindInAllChildren(m_Target); + constraint.data.chainRotationWeight = m_ChainRotationWeight; + constraint.data.tipRotationWeight = m_TipRotationWeight; + constraint.data.maxIterations = m_MaxIterations; + constraint.data.tolerance = m_Tolerance; + constraint.data.maintainTargetPositionOffset = m_MaintainTargetPositionOffset; + constraint.data.maintainTargetRotationOffset = m_MaintainTargetRotationOffset; + } +} diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/ChainIKConstraintReverseAdaptor.cs.meta b/KFAttached/RigAdaptors/ReverseAdaptors/ChainIKConstraintReverseAdaptor.cs.meta new file mode 100644 index 0000000..a1b4153 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/ChainIKConstraintReverseAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d07f318626844d943a83719329ef46e3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/DampedTransformReverseAdaptor.cs b/KFAttached/RigAdaptors/ReverseAdaptors/DampedTransformReverseAdaptor.cs new file mode 100644 index 0000000..95a8d2f --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/DampedTransformReverseAdaptor.cs @@ -0,0 +1,38 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class DampedTransformReverseAdaptor : RigAdaptorAbs +{ + [SerializeField] + private Transform m_ConstrainedObject; + [SerializeField] + private string m_Source; + [SerializeField] + private float m_DampPosition; + [SerializeField] + private float m_DampRotation; + [SerializeField] + private bool m_MaintainAim; + public override void FindRigTargets() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject; + m_Source = constraint.data.sourceObject?.name; + m_DampPosition = constraint.data.dampPosition; + m_DampRotation = constraint.data.dampRotation; + m_MaintainAim = constraint.data.maintainAim; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + constraint.weight = weight; + constraint.data.constrainedObject = m_ConstrainedObject; + constraint.data.sourceObject = targetRoot.FindInAllChildren(m_Source); + constraint.data.dampPosition = m_DampPosition; + constraint.data.dampRotation = m_DampRotation; + constraint.data.maintainAim = m_MaintainAim; + } +} diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/DampedTransformReverseAdaptor.cs.meta b/KFAttached/RigAdaptors/ReverseAdaptors/DampedTransformReverseAdaptor.cs.meta new file mode 100644 index 0000000..98f5512 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/DampedTransformReverseAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 024d749c0fd809c4ba3d82d3a3618415 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/MultiAimConstraintReverseAdaptor.cs b/KFAttached/RigAdaptors/ReverseAdaptors/MultiAimConstraintReverseAdaptor.cs new file mode 100644 index 0000000..fcb324e --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/MultiAimConstraintReverseAdaptor.cs @@ -0,0 +1,69 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class MultiAimConstraintReverseAdaptor : RigAdaptorAbs +{ + [SerializeField] + private Transform m_ConstrainedObject; + [SerializeField] + private string[] m_SourceObjectNames; + [SerializeField] + private float[] m_SourceObjectWeights; + [SerializeField] + private Vector3 m_Offset; + [SerializeField] + private Vector2 m_limits; + [SerializeField] + private MultiAimConstraintData.Axis m_AimAxis; + [SerializeField] + private MultiAimConstraintData.Axis m_UpAxis; + [SerializeField] + private MultiAimConstraintData.WorldUpType m_WorldUpType; + [SerializeField] + private Transform m_WorldUpObject; + [SerializeField] + private MultiAimConstraintData.Axis m_WorldUpAxis; + [SerializeField] + private bool m_MaintainOffset; + [SerializeField] + private Vector3Bool m_ConstrainedAxes; + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.constrainedObject = m_ConstrainedObject; + constraint.data.sourceObjects = WeightedTransformArrayFromAdaptor(targetRoot, m_SourceObjectNames, m_SourceObjectWeights); + constraint.data.offset = m_Offset; + constraint.data.limits = m_limits; + constraint.data.aimAxis = m_AimAxis; + constraint.data.upAxis = m_UpAxis; + constraint.data.worldUpType = m_WorldUpType; + constraint.data.worldUpObject = m_WorldUpObject; + constraint.data.worldUpAxis = m_WorldUpAxis; + constraint.data.maintainOffset = m_MaintainOffset; + constraint.data.constrainedXAxis = m_ConstrainedAxes.x; + constraint.data.constrainedYAxis = m_ConstrainedAxes.y; + constraint.data.constrainedZAxis = m_ConstrainedAxes.z; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject; + WeightedTransformArrayToAdaptor(constraint.data.sourceObjects, out m_SourceObjectNames, out m_SourceObjectWeights); + m_Offset = constraint.data.offset; + m_limits = constraint.data.limits; + m_AimAxis = constraint.data.aimAxis; + m_UpAxis = constraint.data.upAxis; + m_WorldUpType = constraint.data.worldUpType; + if ((m_WorldUpType == MultiAimConstraintData.WorldUpType.ObjectUp || m_WorldUpType == MultiAimConstraintData.WorldUpType.ObjectRotationUp) && constraint.data.worldUpObject) + m_WorldUpObject = constraint.data.worldUpObject; + m_WorldUpAxis = constraint.data.worldUpAxis; + m_MaintainOffset = constraint.data.maintainOffset; + m_ConstrainedAxes = new Vector3Bool(constraint.data.constrainedXAxis, constraint.data.constrainedYAxis, constraint.data.constrainedZAxis); + } +} diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/MultiAimConstraintReverseAdaptor.cs.meta b/KFAttached/RigAdaptors/ReverseAdaptors/MultiAimConstraintReverseAdaptor.cs.meta new file mode 100644 index 0000000..e7a0994 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/MultiAimConstraintReverseAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57060a9b209c4cb489b39a7405f25bcb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/MultiParentConstraintReverseAdaptor.cs b/KFAttached/RigAdaptors/ReverseAdaptors/MultiParentConstraintReverseAdaptor.cs new file mode 100644 index 0000000..e1e919e --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/MultiParentConstraintReverseAdaptor.cs @@ -0,0 +1,49 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class MultiParentConstraintReverseAdaptor : RigAdaptorAbs +{ + [SerializeField] + private Transform m_ConstrainedObject; + [SerializeField] + private string[] m_SourceObjectNames; + [SerializeField] + private float[] m_SourceObjectWeights; + [SerializeField] + private Vector3Bool m_ConstrainedPositionAxes; + [SerializeField] + private Vector3Bool m_ConstrainedRotationAxes; + [SerializeField] + private bool m_MaintainPositionOffset; + [SerializeField] + private bool m_MaintainRotationOffset; + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.constrainedObject = m_ConstrainedObject; + constraint.data.sourceObjects = WeightedTransformArrayFromAdaptor(targetRoot, m_SourceObjectNames, m_SourceObjectWeights); + constraint.data.constrainedPositionXAxis = m_ConstrainedPositionAxes.x; + constraint.data.constrainedPositionYAxis = m_ConstrainedPositionAxes.y; + constraint.data.constrainedPositionZAxis = m_ConstrainedPositionAxes.z; + constraint.data.constrainedRotationXAxis = m_ConstrainedRotationAxes.x; + constraint.data.constrainedRotationYAxis = m_ConstrainedRotationAxes.y; + constraint.data.constrainedRotationZAxis = m_ConstrainedRotationAxes.z; + constraint.data.maintainPositionOffset = m_MaintainPositionOffset; + constraint.data.maintainRotationOffset = m_MaintainRotationOffset; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject; + WeightedTransformArrayToAdaptor(constraint.data.sourceObjects, out m_SourceObjectNames, out m_SourceObjectWeights); + m_ConstrainedPositionAxes = new Vector3Bool(constraint.data.constrainedPositionXAxis, constraint.data.constrainedPositionYAxis, constraint.data.constrainedPositionZAxis); + m_ConstrainedRotationAxes = new Vector3Bool(constraint.data.constrainedRotationXAxis, constraint.data.constrainedRotationYAxis, constraint.data.constrainedRotationZAxis); + m_MaintainPositionOffset = constraint.data.maintainPositionOffset; + m_MaintainRotationOffset = constraint.data.maintainRotationOffset; + } +} diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/MultiParentConstraintReverseAdaptor.cs.meta b/KFAttached/RigAdaptors/ReverseAdaptors/MultiParentConstraintReverseAdaptor.cs.meta new file mode 100644 index 0000000..01d9458 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/MultiParentConstraintReverseAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e4720f809bab89e4bab5459297567d0c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/MultiPositionConstraintReverseAdaptor.cs b/KFAttached/RigAdaptors/ReverseAdaptors/MultiPositionConstraintReverseAdaptor.cs new file mode 100644 index 0000000..d73688e --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/MultiPositionConstraintReverseAdaptor.cs @@ -0,0 +1,44 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class MultiPositionConstraintReverseAdaptor : RigAdaptorAbs +{ + [SerializeField] + private Transform m_ConstrainedObject; + [SerializeField] + private string[] m_SourceObjectNames; + [SerializeField] + private float[] m_SourceObjectWeights; + [SerializeField] + private Vector3 m_Offset; + [SerializeField] + private Vector3Bool m_ConstrainedAxes; + [SerializeField] + private bool m_MaintainOffset; + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.constrainedObject = m_ConstrainedObject; + constraint.data.sourceObjects = WeightedTransformArrayFromAdaptor(targetRoot, m_SourceObjectNames, m_SourceObjectWeights); + constraint.data.offset = m_Offset; + constraint.data.constrainedXAxis = m_ConstrainedAxes.x; + constraint.data.constrainedYAxis = m_ConstrainedAxes.y; + constraint.data.constrainedZAxis = m_ConstrainedAxes.z; + constraint.data.maintainOffset = m_MaintainOffset; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject; + WeightedTransformArrayToAdaptor(constraint.data.sourceObjects, out m_SourceObjectNames, out m_SourceObjectWeights); + m_Offset = constraint.data.offset; + m_ConstrainedAxes = new Vector3Bool(constraint.data.constrainedXAxis, constraint.data.constrainedYAxis, constraint.data.constrainedZAxis); + m_MaintainOffset = constraint.data.maintainOffset; + } +} diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/MultiPositionConstraintReverseAdaptor.cs.meta b/KFAttached/RigAdaptors/ReverseAdaptors/MultiPositionConstraintReverseAdaptor.cs.meta new file mode 100644 index 0000000..06df0d8 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/MultiPositionConstraintReverseAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 700d88da068a59848930b99154a10879 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/MultiReferentialConstraintReverseAdaptor.cs b/KFAttached/RigAdaptors/ReverseAdaptors/MultiReferentialConstraintReverseAdaptor.cs new file mode 100644 index 0000000..43b8303 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/MultiReferentialConstraintReverseAdaptor.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class MultiReferentialConstraintReverseAdaptor : RigAdaptorAbs +{ + [SerializeField] + private int m_Driver; + [SerializeField] + private List m_SourceObjects; + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.driver = m_Driver; + constraint.data.sourceObjects = new List(); + foreach(var sourceObject in m_SourceObjects) + { + constraint.data.sourceObjects.Add(targetRoot.FindInAllChildren(sourceObject)); + } + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_Driver = constraint.data.driver; + m_SourceObjects = new List(); + foreach (var sourceObject in constraint.data.sourceObjects) + { + m_SourceObjects.Add(sourceObject?.name); + } + } +} diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/MultiReferentialConstraintReverseAdaptor.cs.meta b/KFAttached/RigAdaptors/ReverseAdaptors/MultiReferentialConstraintReverseAdaptor.cs.meta new file mode 100644 index 0000000..0b5e2b4 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/MultiReferentialConstraintReverseAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c564e8b8f4881e6498f344db3bbd63b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/MultiRotationConstraintReverseAdaptor.cs b/KFAttached/RigAdaptors/ReverseAdaptors/MultiRotationConstraintReverseAdaptor.cs new file mode 100644 index 0000000..9c3a819 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/MultiRotationConstraintReverseAdaptor.cs @@ -0,0 +1,44 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class MultiRotationConstraintReverseAdaptor : RigAdaptorAbs +{ + [SerializeField] + private Transform m_ConstrainedObject; + [SerializeField] + private string[] m_SourceObjectNames; + [SerializeField] + private float[] m_SourceObjectWeights; + [SerializeField] + private Vector3 m_Offset; + [SerializeField] + private Vector3Bool m_ConstrainedAxes; + [SerializeField] + private bool m_MaintainOffset; + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.constrainedObject = m_ConstrainedObject; + constraint.data.sourceObjects = WeightedTransformArrayFromAdaptor(targetRoot, m_SourceObjectNames, m_SourceObjectWeights); + constraint.data.offset = m_Offset; + constraint.data.constrainedXAxis = m_ConstrainedAxes.x; + constraint.data.constrainedYAxis = m_ConstrainedAxes.y; + constraint.data.constrainedZAxis = m_ConstrainedAxes.z; + constraint.data.maintainOffset = m_MaintainOffset; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject; + WeightedTransformArrayToAdaptor(constraint.data.sourceObjects, out m_SourceObjectNames, out m_SourceObjectWeights); + m_Offset = constraint.data.offset; + m_ConstrainedAxes = new Vector3Bool(constraint.data.constrainedXAxis, constraint.data.constrainedYAxis, constraint.data.constrainedZAxis); + m_MaintainOffset = constraint.data.maintainOffset; + } +} diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/MultiRotationConstraintReverseAdaptor.cs.meta b/KFAttached/RigAdaptors/ReverseAdaptors/MultiRotationConstraintReverseAdaptor.cs.meta new file mode 100644 index 0000000..ae26b20 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/MultiRotationConstraintReverseAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6b08d9d6ae2d5244b83a65aacd535ab8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/OverrideTransformReverseAdaptor.cs b/KFAttached/RigAdaptors/ReverseAdaptors/OverrideTransformReverseAdaptor.cs new file mode 100644 index 0000000..0f4f190 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/OverrideTransformReverseAdaptor.cs @@ -0,0 +1,48 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class OverrideTransformReverseAdaptor : RigAdaptorAbs +{ + [SerializeField] + private Transform m_ConstrainedObject; + [SerializeField] + private string m_OverrideSource; + [SerializeField] + private Vector3 m_OverridePosition; + [SerializeField] + private Vector3 m_OverrideRotation; + [SerializeField] + private float m_PositionWeight; + [SerializeField] + private float m_RotationWeight; + [SerializeField] + private OverrideTransformData.Space m_Space; + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.constrainedObject = m_ConstrainedObject; + constraint.data.sourceObject = targetRoot.FindInAllChildren(m_OverrideSource); + constraint.data.position = m_OverridePosition; + constraint.data.rotation = m_OverrideRotation; + constraint.data.positionWeight = m_PositionWeight; + constraint.data.rotationWeight = m_RotationWeight; + constraint.data.space = m_Space; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_ConstrainedObject = constraint.data.constrainedObject; + m_OverrideSource = constraint.data.sourceObject?.name; + m_OverridePosition = constraint.data.position; + m_OverrideRotation = constraint.data.rotation; + m_PositionWeight = constraint.data.positionWeight; + m_RotationWeight = constraint.data.rotationWeight; + m_Space = constraint.data.space; + } +} diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/OverrideTransformReverseAdaptor.cs.meta b/KFAttached/RigAdaptors/ReverseAdaptors/OverrideTransformReverseAdaptor.cs.meta new file mode 100644 index 0000000..a86cc4f --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/OverrideTransformReverseAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d6971ec144ef3f84b8c6ce116c7ea3de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/TwistChainConstraintReverseAdaptor.cs b/KFAttached/RigAdaptors/ReverseAdaptors/TwistChainConstraintReverseAdaptor.cs new file mode 100644 index 0000000..724e47f --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/TwistChainConstraintReverseAdaptor.cs @@ -0,0 +1,40 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class TwistChainConstraintReverseAdaptor : RigAdaptorAbs +{ + [SerializeField] + private Transform m_Root; + [SerializeField] + private Transform m_Tip; + [SerializeField] + private string m_RootTarget; + [SerializeField] + private string m_TipTarget; + [SerializeField] + private AnimationCurve m_Curve; + + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.root = m_Root; + constraint.data.tip = m_Tip; + constraint.data.rootTarget = targetRoot.FindInAllChildren(m_RootTarget); + constraint.data.tipTarget = targetRoot.FindInAllChildren(m_TipTarget); + constraint.data.curve = m_Curve; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_Root = constraint.data.root; + m_Tip = constraint.data.tip; + m_RootTarget = constraint.data.rootTarget?.name; + m_TipTarget = constraint.data.tipTarget?.name; + m_Curve = constraint.data.curve; + } +} diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/TwistChainConstraintReverseAdaptor.cs.meta b/KFAttached/RigAdaptors/ReverseAdaptors/TwistChainConstraintReverseAdaptor.cs.meta new file mode 100644 index 0000000..ed67847 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/TwistChainConstraintReverseAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 769f53150f7d575498374023f393136c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/TwistCorrectionReverseAdaptor.cs b/KFAttached/RigAdaptors/ReverseAdaptors/TwistCorrectionReverseAdaptor.cs new file mode 100644 index 0000000..ae414d6 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/TwistCorrectionReverseAdaptor.cs @@ -0,0 +1,15 @@ +using System.Linq; +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class TwistCorrectionReverseAdaptor : RigAdaptorAbs +{ + public override void FindRigTargets() + { + } + + public override void ReadRigData() + { + } +} diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/TwistCorrectionReverseAdaptor.cs.meta b/KFAttached/RigAdaptors/ReverseAdaptors/TwistCorrectionReverseAdaptor.cs.meta new file mode 100644 index 0000000..a7a6a5a --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/TwistCorrectionReverseAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a25e34cfebf5e5e45a0be99dad327b64 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/TwoBoneIKConstraintReverseAdaptor.cs b/KFAttached/RigAdaptors/ReverseAdaptors/TwoBoneIKConstraintReverseAdaptor.cs new file mode 100644 index 0000000..6c79278 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/TwoBoneIKConstraintReverseAdaptor.cs @@ -0,0 +1,59 @@ +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("")] +public class TwoBoneIKConstraintReverseAdaptor : RigAdaptorAbs +{ + [SerializeField] + private Transform m_Root; + [SerializeField] + private Transform m_Mid; + [SerializeField] + private Transform m_Tip; + [SerializeField] + private string m_Target; + [SerializeField] + private string m_Hint; + [SerializeField] + private float m_TargetPositionWeight; + [SerializeField] + private float m_TargetRotationWeight; + [SerializeField] + private float m_HintWeight; + [SerializeField] + private bool m_MaintainTargetPositionOffset; + [SerializeField] + private bool m_MaintainTargetRotationOffset; + public override void FindRigTargets() + { + var constraint = GetComponent(); + constraint.Reset(); + constraint.weight = weight; + constraint.data.root = m_Root; + constraint.data.mid = m_Mid; + constraint.data.tip = m_Tip; + constraint.data.target = targetRoot.FindInAllChildren(m_Target); + constraint.data.hint = targetRoot.FindInAllChildren(m_Hint); + constraint.data.targetPositionWeight = m_TargetPositionWeight; + constraint.data.targetRotationWeight = m_TargetRotationWeight; + constraint.data.hintWeight = m_HintWeight; + constraint.data.maintainTargetPositionOffset = m_MaintainTargetPositionOffset; + constraint.data.maintainTargetRotationOffset = m_MaintainTargetRotationOffset; + } + + public override void ReadRigData() + { + var constraint = GetComponent(); + weight = constraint.weight; + m_Root = constraint.data.root; + m_Mid = constraint.data.mid; + m_Tip = constraint.data.tip; + m_Target = constraint.data.target?.name; + m_Hint = constraint.data.hint?.name; + m_TargetPositionWeight = constraint.data.targetPositionWeight; + m_TargetRotationWeight = constraint.data.targetRotationWeight; + m_HintWeight = constraint.data.hintWeight; + m_MaintainTargetPositionOffset = constraint.data.maintainTargetPositionOffset; + m_MaintainTargetRotationOffset = constraint.data.maintainTargetRotationOffset; + } +} diff --git a/KFAttached/RigAdaptors/ReverseAdaptors/TwoBoneIKConstraintReverseAdaptor.cs.meta b/KFAttached/RigAdaptors/ReverseAdaptors/TwoBoneIKConstraintReverseAdaptor.cs.meta new file mode 100644 index 0000000..ccc1523 --- /dev/null +++ b/KFAttached/RigAdaptors/ReverseAdaptors/TwoBoneIKConstraintReverseAdaptor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9347c9017333b794d8117c27ec493d06 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/RigConverter.cs b/KFAttached/RigAdaptors/RigConverter.cs new file mode 100644 index 0000000..db86555 --- /dev/null +++ b/KFAttached/RigAdaptors/RigConverter.cs @@ -0,0 +1,309 @@ +#if UNITY_EDITOR +using System; +using UnityEditor; +using UnityEngine.Animations.Rigging; +#endif +using UnityEngine; +using System.Linq; + +[AddComponentMenu("KFAttachments/RigAdaptors/Rig Converter")] +public class RigConverter : MonoBehaviour +{ + public Transform targetRoot; + +#if UNITY_EDITOR + [ContextMenu("Convert Rig Constraints to Adaptors")] + private void Convert() + { + foreach (var constraint in GetComponentsInChildren(true)) + { + if (constraint.component.TryGetComponent(out var role) && role.role == RigConverterRole.Role.Ignore) + { + continue; + } + var adaptorName = constraint.GetType().Name; + if (role && role.role == RigConverterRole.Role.Reverse) + { + adaptorName += "Reverse"; + } + adaptorName += "Adaptor,KFCommonUtilityLib"; + var adaptorType = Type.GetType(adaptorName); + var adaptor = (RigAdaptorAbs)constraint.component.transform.AddMissingComponent(adaptorType); + adaptor.ReadRigData(); + adaptor.hideFlags = HideFlags.NotEditable; + EditorUtility.SetDirty(adaptor); + } + Save(); + } + + [ContextMenu("Read Adaptor Value to Constraints")] + private void Read() + { + Rebind(); + Save(); + } + + [ContextMenu("Remove All Adaptors")] + private void RemoveAll() + { + var constraints = GetComponentsInChildren(true); + foreach (var constraint in constraints) + { + DestroyImmediate(constraint); + } + Save(); + } + + [ContextMenu("Fix A22 Constraints")] + private void Fix() + { + Rebind(); + foreach (var constraint in GetComponentsInChildren()) + { + string name = constraint.component.transform.name; + if (char.IsDigit(name[^1])) + { + if (name.Contains("ArmRollCorrections") && constraint.component is MultiRotationConstraint mrcArm) + { + int index = int.Parse(name.Substring(name.Length - 1, 1)); + var source = mrcArm.data.sourceObjects; + source.SetWeight(0, index * 0.25f); + mrcArm.data.sourceObjects = source; + mrcArm.data.constrainedXAxis = true; + mrcArm.data.constrainedYAxis = false; + mrcArm.data.constrainedZAxis = false; + } + else if (name.Contains("FingerTarget") && name.Length == 13 && constraint.component is TwoBoneIKConstraint tbc) + { + int index = int.Parse(name.Substring(name.Length - 1, 1)); + string targetNameBase = tbc.data.root.transform.name[..^1]; + tbc.data.root = targetRoot.FindInAllChildren($"{targetNameBase}1"); + tbc.data.mid = targetRoot.FindInAllChildren($"{targetNameBase}{(index == 5 ? 3 : 2)}"); + tbc.data.tip = targetRoot.FindInAllChildren($"{targetNameBase}4"); + } + else if (name.Contains("FingerTargetRollCorrection") && constraint.component is MultiRotationConstraint mrcFinger) + { + int index = int.Parse(name.Substring(name.Length - 1, 1)); + mrcFinger.data.constrainedXAxis = true; + mrcFinger.data.constrainedYAxis = false; + mrcFinger.data.constrainedZAxis = index == 1; + } + } + } + Convert(); + } + + [ContextMenu("Convert To New Rig Setup")] + private void Renew() + { + Rebind(); + string leftHandTransName = null, rightHandTransName = null; + foreach (var tbik in GetComponentsInChildren()) + { + if(tbik.data.tip.name.Contains("hand", StringComparison.OrdinalIgnoreCase)) + { + Transform target = tbik.data.target; + if(target.name.Contains("target", StringComparison.OrdinalIgnoreCase)) + { + target = target.parent; + } + if (tbik.data.tip.name.StartsWith("Left", StringComparison.OrdinalIgnoreCase)) + { + leftHandTransName = target.name; + } + else + { + rightHandTransName = target.name; + } + } + } + if(leftHandTransName == null || rightHandTransName == null) + { + Log.Error("Left/Right hand transform not found on weapon skeleton!"); + return; + } + foreach (var constraint in GetComponentsInChildren()) + { + Transform trans = constraint.component.transform; + string name = trans.name; + if (char.IsDigit(name[^1]) && name.StartsWith("FingerTarget") && !trans.parent.name.StartsWith("FingerTarget") && constraint is TwoBoneIKConstraint tbik) + { + int index = int.Parse(name.Substring(name.Length - 1, 1)); + if(index > 4) + { + continue; + } + GameObject newConstraint = new(name); + newConstraint.transform.SetParent(trans, true); + newConstraint.transform.SetAsFirstSibling(); + newConstraint.transform.position = trans.position; + EditorUtility.CopySerialized(tbik, newConstraint.AddComponent()); + DestroyImmediate(tbik); + if (trans.GetComponent() is TwoBoneIKConstraintAdaptor adaptor) + { + DestroyImmediate(adaptor); + } + + string targetNameBase = tbik.data.root.transform.name[..^1]; + bool isLeft = targetNameBase.StartsWith("Left"); + GameObject metacarpal = new($"MetacarpalAiming{index}"); + var aimConstraint = metacarpal.AddComponent(); + aimConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{targetNameBase}0"); + aimConstraint.data.aimAxis = isLeft ? MultiAimConstraintData.Axis.X_NEG : MultiAimConstraintData.Axis.X; + aimConstraint.data.upAxis = isLeft ? MultiAimConstraintData.Axis.Y : MultiAimConstraintData.Axis.Y_NEG; + aimConstraint.data.worldUpType = MultiAimConstraintData.WorldUpType.None; + aimConstraint.data.constrainedXAxis = false; + aimConstraint.data.constrainedYAxis = false; + aimConstraint.data.constrainedZAxis = true; + Transform curSource = tbik.data.target; + while(((isLeft && curSource.parent.parent.name != leftHandTransName) || (!isLeft && curSource.parent.parent.name != rightHandTransName)) && !curSource.parent.name.Contains("1")) + { + curSource = curSource.parent; + } + var sourceArr = aimConstraint.data.sourceObjects; + var source = new WeightedTransform(curSource.parent.name.Contains("1") ? curSource.parent : curSource, 1); + sourceArr.Add(source); + aimConstraint.data.sourceObjects = sourceArr; + metacarpal.transform.SetParent(trans.transform); + metacarpal.transform.SetAsFirstSibling(); + } + } + Convert(); + } + + public void CreateEmpty() + { + CreateEmptyForSide("Left"); + CreateEmptyForSide("Right"); + } + + private static string[] PhalangeBoneNames = new[] + { + "Thumb", + "Index", + "Middle", + "Pinky", + "Ring" + }; + + private void CreateEmptyForSide(string side) + { + WeightedTransformArray sourceObjects = new(); + + Transform shoulderReposition = new GameObject($"{side}ShoulderReposition").transform; + shoulderReposition.parent = transform; + MultiPositionConstraint shoulderRepositionConstraint = shoulderReposition.gameObject.AddComponent(); + shoulderRepositionConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{side}Shoulder"); + shoulderRepositionConstraint.data.constrainedXAxis = shoulderRepositionConstraint.data.constrainedYAxis = shoulderRepositionConstraint.data.constrainedZAxis = true; + + Transform armRollCorrection = new GameObject($"{side}ArmRollCorrections").transform; + armRollCorrection.parent = transform; + for (int i = 1; i <= 4; i++) + { + Transform child = new GameObject($"{armRollCorrection.name}{i}").transform; + child.parent = armRollCorrection; + MultiRotationConstraint armRollCorrectionConstraint = child.gameObject.AddComponent(); + armRollCorrectionConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{side}ForeArmRoll{i}"); + armRollCorrectionConstraint.data.constrainedXAxis = true; + armRollCorrectionConstraint.data.constrainedYAxis = false; + armRollCorrectionConstraint.data.constrainedZAxis = false; + sourceObjects.Add(new WeightedTransform(null, i * .25f)); + armRollCorrectionConstraint.data.sourceObjects = sourceObjects; + sourceObjects.Clear(); + } + + Transform armTarget = new GameObject($"{side}ArmTarget").transform; + armTarget.parent = transform; + TwoBoneIKConstraint armTargetConstraint = armTarget.gameObject.AddComponent(); + armTargetConstraint.data.root = targetRoot.FindInAllChildren($"{side}Arm"); + armTargetConstraint.data.mid = targetRoot.FindInAllChildren($"{side}ForeArm"); + armTargetConstraint.data.tip = targetRoot.FindInAllChildren($"{side}Hand"); + + bool isLeft = side == "Left"; + Transform handTargets = new GameObject($"{side}HandTargets").transform; + handTargets.parent = transform; + for (int i = 1; i <= 4; i++) + { + string fingerTargetName = $"FingerTarget{i}"; + Transform fingerTargetParent = new GameObject(fingerTargetName).transform; + fingerTargetParent.parent = handTargets; + + Transform metacarpalAiming = new GameObject($"MetacarpalAiming{i}").transform; + metacarpalAiming.parent = fingerTargetParent; + MultiAimConstraint metacarpalAimingConstraint = metacarpalAiming.gameObject.AddComponent(); + metacarpalAimingConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{side}Hand{PhalangeBoneNames[i]}0"); + metacarpalAimingConstraint.data.aimAxis = isLeft ? MultiAimConstraintData.Axis.X_NEG : MultiAimConstraintData.Axis.X; + metacarpalAimingConstraint.data.upAxis = isLeft ? MultiAimConstraintData.Axis.Y : MultiAimConstraintData.Axis.Y_NEG; + metacarpalAimingConstraint.data.worldUpType = MultiAimConstraintData.WorldUpType.None; + metacarpalAimingConstraint.data.constrainedXAxis = false; + metacarpalAimingConstraint.data.constrainedYAxis = false; + metacarpalAimingConstraint.data.constrainedZAxis = true; + + Transform fingerTarget = new GameObject(fingerTargetName).transform; + fingerTarget.parent = fingerTargetParent; + TwoBoneIKConstraint fingerTargetConstraint = fingerTarget.gameObject.AddComponent(); + fingerTargetConstraint.data.root = targetRoot.FindInAllChildren($"{side}Hand{PhalangeBoneNames[i]}1"); + fingerTargetConstraint.data.mid = targetRoot.FindInAllChildren($"{side}Hand{PhalangeBoneNames[i]}2"); + fingerTargetConstraint.data.tip = targetRoot.FindInAllChildren($"{side}Hand{PhalangeBoneNames[i]}4"); + } + + Transform thumbTargetParent = new GameObject("FingerTarget5").transform; + thumbTargetParent.parent = handTargets; + + Transform thumbTargetRollCorrection1 = new GameObject("FingerTargetRollCorrection1").transform; + thumbTargetRollCorrection1.parent = thumbTargetParent; + MultiRotationConstraint thumbTargetRollCorrectionConstraint = thumbTargetRollCorrection1.gameObject.AddComponent(); + thumbTargetRollCorrectionConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{side}HandThumb1"); + thumbTargetRollCorrectionConstraint.data.constrainedXAxis = thumbTargetRollCorrectionConstraint.data.constrainedYAxis = thumbTargetRollCorrectionConstraint.data.constrainedZAxis = true; + sourceObjects.Add(new WeightedTransform(null, .5f)); + thumbTargetRollCorrectionConstraint.data.sourceObjects = sourceObjects; + sourceObjects.Clear(); + + Transform thumbTargetRollCorrection2 = new GameObject("FingerTargetRollCorrection2").transform; + thumbTargetRollCorrection2.parent = thumbTargetParent; + thumbTargetRollCorrectionConstraint = thumbTargetRollCorrection2.gameObject.AddComponent(); + thumbTargetRollCorrectionConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{side}HandThumb2"); + thumbTargetRollCorrectionConstraint.data.constrainedXAxis = true; + thumbTargetRollCorrectionConstraint.data.constrainedYAxis = false; + thumbTargetRollCorrectionConstraint.data.constrainedZAxis = false; + sourceObjects.Add(new WeightedTransform(null, .3f)); + thumbTargetRollCorrectionConstraint.data.sourceObjects = sourceObjects; + sourceObjects.Clear(); + + Transform thumbTargetRollCorrection3 = new GameObject("FingerTargetRollCorrection3").transform; + thumbTargetRollCorrection3.parent = thumbTargetParent; + thumbTargetRollCorrectionConstraint = thumbTargetRollCorrection3.gameObject.AddComponent(); + thumbTargetRollCorrectionConstraint.data.constrainedObject = targetRoot.FindInAllChildren($"{side}HandThumb3"); + thumbTargetRollCorrectionConstraint.data.constrainedXAxis = true; + thumbTargetRollCorrectionConstraint.data.constrainedYAxis = false; + thumbTargetRollCorrectionConstraint.data.constrainedZAxis = false; + sourceObjects.Add(new WeightedTransform(null, .2f)); + thumbTargetRollCorrectionConstraint.data.sourceObjects = sourceObjects; + sourceObjects.Clear(); + + Transform thumbTarget = new GameObject("FingerTarget5").transform; + thumbTarget.parent = thumbTargetParent; + TwoBoneIKConstraint thumbTargetConstraint = thumbTarget.gameObject.AddComponent(); + thumbTargetConstraint.data.root = targetRoot.FindInAllChildren($"{side}HandThumb1"); + thumbTargetConstraint.data.mid = targetRoot.FindInAllChildren($"{side}HandThumb3"); + thumbTargetConstraint.data.tip = targetRoot.FindInAllChildren($"{side}HandThumb4"); + thumbTargetConstraint.data.targetRotationWeight = 0; + } + + private void Save() + { + var root = GetComponentInParent(true).gameObject; + if(PrefabUtility.IsOutermostPrefabInstanceRoot(root)) + PrefabUtility.ApplyPrefabInstance(root, InteractionMode.AutomatedAction); + } +#endif + + public void Rebind() + { + foreach (var adaptor in GetComponentsInChildren(true)) + { + adaptor.targetRoot = targetRoot; + adaptor.FindRigTargets(); + } + } +} diff --git a/KFAttached/RigAdaptors/RigConverter.cs.meta b/KFAttached/RigAdaptors/RigConverter.cs.meta new file mode 100644 index 0000000..72fdd1c --- /dev/null +++ b/KFAttached/RigAdaptors/RigConverter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a3d68c3fc2fae4143b22cdc25d70652e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/RigConverterRole.cs b/KFAttached/RigAdaptors/RigConverterRole.cs new file mode 100644 index 0000000..4552368 --- /dev/null +++ b/KFAttached/RigAdaptors/RigConverterRole.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +[AddComponentMenu("KFAttachments/RigAdaptors/Rig Converter Ignore")] +public class RigConverterRole : MonoBehaviour +{ + public enum Role + { + Normal, + Reverse, + Ignore + } + + public Role role; +} diff --git a/KFAttached/RigAdaptors/RigConverterRole.cs.meta b/KFAttached/RigAdaptors/RigConverterRole.cs.meta new file mode 100644 index 0000000..7436ac0 --- /dev/null +++ b/KFAttached/RigAdaptors/RigConverterRole.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d0ab4e79948fd2844a1e3857e46066dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/RigTargets.cs b/KFAttached/RigAdaptors/RigTargets.cs new file mode 100644 index 0000000..5cfbee2 --- /dev/null +++ b/KFAttached/RigAdaptors/RigTargets.cs @@ -0,0 +1,183 @@ +#if NotEditor +using KFCommonUtilityLib.Scripts.StaticManagers; +using UniLinq; +#else +using System.Linq; +#endif +using System.Diagnostics; +using UnityEngine; +using UnityEngine.Animations.Rigging; + +[AddComponentMenu("KFAttachments/RigAdaptors/Rig Targets")] +public class RigTargets : AnimationTargetsAbs +{ + [Header("Fpv Fields")] + [SerializeField] + public Transform itemFpv; + [SerializeField] + public Rig rig; + [SerializeField] + public Transform attachmentReference; + + private RigLayer rigLayerFpv; + + private Animator itemAnimator; + + public override Transform ItemFpv { get => itemFpv; protected set => itemFpv = value; } + public override Transform AttachmentRef { get => attachmentReference; protected set => attachmentReference = value; } + protected override Animator ItemAnimatorFpv => itemAnimator; + protected override void Awake() + { + base.Awake(); + if (!itemFpv) + return; + itemAnimator = itemFpv.GetComponentInChildren(true); +#if NotEditor + itemAnimator.writeDefaultValuesOnDisable = true; +#endif +#if NotEditor + rig.gameObject.name += $"_UID_{TypeBasedUID.UID}"; + AnimationRiggingManager.AddRigExcludeName(rig.gameObject.name); + + itemFpv.gameObject.SetActive(false); +#endif + } + + protected override void Init() + { + base.Init(); + if (!itemFpv) + { + return; + } + + if (IsFpv) + { + if (ItemAnimatorFpv.TryGetComponent(out var delayRenderer)) + { + Destroy(delayRenderer); + } + itemFpv.SetParent(PlayerAnimatorTrans.parent, false); + itemFpv.SetAsFirstSibling(); + itemFpv.position = Vector3.zero; + itemFpv.localPosition = Vector3.zero; + itemFpv.localRotation = Quaternion.identity; + var rc = rig.GetComponent(); + rc.targetRoot = PlayerAnimatorTrans; + rc.Rebind(); + } + else + { + itemFpv.SetParent(PlayerAnimatorTrans.parent); + itemFpv.position = Vector3.zero; + itemFpv.localPosition = Vector3.zero; + itemFpv.localRotation = Quaternion.identity; + } + //Log.Out($"set parent to {PlayerAnimatorTrans.parent.parent.name}/{PlayerAnimatorTrans.parent.name}\n{StackTraceUtility.ExtractStackTrace()}"); + +//#if NotEditor +// Utils.SetLayerRecursively(itemFpv.gameObject, 10, Utils.ExcludeLayerZoom); +// Utils.SetLayerRecursively(gameObject, 24, Utils.ExcludeLayerZoom); +//#endif + //LogInfo(itemFpv.localPosition.ToString() + " / " + itemFpv.localEulerAngles.ToString()); + } + + protected override bool SetupFpv() + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + rig.transform.SetParent(PlayerAnimatorTrans, false); + rig.transform.position = Vector3.zero; + rig.transform.localPosition = Vector3.zero; + rig.transform.localRotation = Quaternion.identity; + + var rigBuilder = PlayerAnimatorTrans.AddMissingComponent(); + rigBuilder.layers.Insert(0, rigLayerFpv = new RigLayer(rig, true)); +#if NotEditor + foreach (var layer in rigBuilder.layers) + { + if (layer.name == SDCSUtils.IKRIG) + { + layer.active = false; + } + } +#endif + BuildRig(rigBuilder.GetComponent(), rigBuilder); + sw.Stop(); + string info = $"setup animation rig took {sw.ElapsedMilliseconds} ms"; + //info += $"\n{StackTraceUtility.ExtractStackTrace()}"; + Log.Out(info); + return true; + } + + protected override void RemoveFpv() + { + Stopwatch sw = new Stopwatch(); + sw.Start(); + + var rigBuilder = PlayerAnimatorTrans.AddMissingComponent(); + int removed = rigBuilder.layers.RemoveAll(r => r.name == rigLayerFpv.name); +//#if NotEditor +// Log.Out($"Removed {removed} layers, remaining:\n{string.Join("\n", rigBuilder.layers.Select(layer => layer.name))}"); +//#endif + rig.transform.SetParent(transform, false); + rig.gameObject.SetActive(false); + rigLayerFpv = null; +#if NotEditor + foreach (var layer in rigBuilder.layers) + { + if (layer.name == SDCSUtils.IKRIG) + { + layer.active = true; + } + } +#endif + BuildRig(rigBuilder.GetComponent(), rigBuilder); + sw.Stop(); + string info = $"destroy animation rig took {sw.ElapsedMilliseconds} ms"; + //info += $"\n{StackTraceUtility.ExtractStackTrace()}"; + Log.Out(info); + } + + public override void DestroyFpv() + { +#if NotEditor + if (rig) + { + AnimationRiggingManager.RemoveRigExcludeName(rig.gameObject.name); + } +#endif + base.DestroyFpv(); + if (rig) + { + rig.transform.parent = null; + GameObject.DestroyImmediate(rig.gameObject); + } + rig = null; + } + + public override void SetEnabled(bool enabled) + { + //var t = new StackTrace(); + + //LogInfo($"set enabled {isFPV} stack trace:\n{t.ToString()}"); + if (itemFpv) + { + itemFpv.localPosition = enabled ? Vector3.zero : new Vector3(0, -100, 0); + } + base.SetEnabled(enabled); +#if NotEditor + if (enabled && IsFpv && ItemAnimatorFpv && !ItemAnimatorFpv.TryGetComponent(out var delayRenderer)) + { + delayRenderer = ItemAnimatorFpv.gameObject.AddComponent(); + } +#endif + } + +#if NotEditor + public override void UpdatePlayerAvatar(AvatarController avatarController, bool rigWeaponChanged) + { + base.UpdatePlayerAvatar(avatarController, rigWeaponChanged); + } +#endif +} diff --git a/KFAttached/RigAdaptors/RigTargets.cs.meta b/KFAttached/RigAdaptors/RigTargets.cs.meta new file mode 100644 index 0000000..9ee893c --- /dev/null +++ b/KFAttached/RigAdaptors/RigTargets.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7b5aed79c0403ae438dd1f929cc1391e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Utils.meta b/KFAttached/RigAdaptors/Utils.meta new file mode 100644 index 0000000..b7c1fc5 --- /dev/null +++ b/KFAttached/RigAdaptors/Utils.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bfcfb8cce097e304f91fab84a5e76ed8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Utils/InventorySlotGurad.cs b/KFAttached/RigAdaptors/Utils/InventorySlotGurad.cs new file mode 100644 index 0000000..a5b86d3 --- /dev/null +++ b/KFAttached/RigAdaptors/Utils/InventorySlotGurad.cs @@ -0,0 +1,25 @@ +public class InventorySlotGurad +{ + public int Slot { get; private set; } = -1; + +#if NotEditor + public bool IsValid(EntityAlive entity) + { + if (entity && entity.inventory != null) + { + if (Slot < 0) + { + Slot = entity.inventory.holdingItemIdx; + return true; + } + if (Slot != entity.inventory.holdingItemIdx) + { + Log.Warning($"trying to set ammo for slot {Slot} while holding slot {entity.inventory.holdingItemIdx} on entity {entity.entityId}!"); + return false; + } + return true; + } + return false; + } +#endif +} diff --git a/KFAttached/RigAdaptors/Utils/InventorySlotGurad.cs.meta b/KFAttached/RigAdaptors/Utils/InventorySlotGurad.cs.meta new file mode 100644 index 0000000..d38bc39 --- /dev/null +++ b/KFAttached/RigAdaptors/Utils/InventorySlotGurad.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5cf53ce461844eb4eb8f418707f838d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Utils/KFExtensions.cs b/KFAttached/RigAdaptors/Utils/KFExtensions.cs new file mode 100644 index 0000000..65b67af --- /dev/null +++ b/KFAttached/RigAdaptors/Utils/KFExtensions.cs @@ -0,0 +1,431 @@ +using System; +using UnityEngine; + +public static class KFExtensions +{ + public static Transform FindInAllChildren(this Transform target, string name, bool onlyActive = false) + { + if (name == null) + { + return null; + } + + if (!onlyActive || (onlyActive && (bool)target.gameObject && target.gameObject.activeSelf)) + { + if (target.name == name) + { + return target; + } + + for (int i = 0; i < target.childCount; i++) + { + Transform transform = target.GetChild(i).FindInAllChildren(name, onlyActive); + if (transform != null) + { + return transform; + } + } + + return null; + } + + return null; + } + public static T AddMissingComponent(this Transform transform) where T : Component + { + if (!transform.TryGetComponent(out var val)) + { + val = transform.gameObject.AddComponent(); + } + + return val; + } + public static Component AddMissingComponent(this Transform transform, Type type) + { + if (!transform.TryGetComponent(type, out var val)) + { + val = transform.gameObject.AddComponent(type); + } + + return val; + } + public static void RotateAroundPivot(this Transform self, Transform pivot, Vector3 angles) + { + Vector3 dir = self.InverseTransformVector(self.position - pivot.position); // get point direction relative to pivot + Quaternion rot = Quaternion.Euler(angles); + dir = rot * dir; // rotate it + self.localPosition = dir + self.InverseTransformPoint(pivot.position); // calculate rotated point + self.localRotation = rot; + } + + public static void RotateAroundPivot(this Transform self, Transform pivot, Quaternion rotation) + { + Vector3 dir = self.InverseTransformVector(self.position - pivot.position); // get point direction relative to pivot + dir = rotation * dir; // rotate it + self.localPosition = dir + self.InverseTransformPoint(pivot.position); // calculate rotated point + self.localRotation = rotation; + } + + public static Vector3 Random(Vector3 min, Vector3 max) + { + return new Vector3(UnityEngine.Random.Range(min.x, max.x), UnityEngine.Random.Range(min.y, max.y), UnityEngine.Random.Range(min.z, max.z)); + } + + public static Vector3 Clamp(Vector3 val, Vector3 min, Vector3 max) + { + return new Vector3(Mathf.Clamp(val.x, min.x, max.x), Mathf.Clamp(val.y, min.y, max.y), Mathf.Clamp(val.z, min.z, max.z)); + } + + public static Vector3 SmoothStep(Vector3 from, Vector3 to, float t) + { + return new Vector3(Mathf.SmoothStep(from.x, to.x, t), Mathf.SmoothStep(from.y, to.y, t), Mathf.SmoothStep(from.z, to.z, t)); + } + + public static float AngleToInferior(float angle) + { + angle %= 360; + angle = angle > 180 ? angle - 360 : angle; + return angle; + } + + public static Vector3 AngleToInferior(Vector3 angle) + { + return new Vector3(AngleToInferior(angle.x), AngleToInferior(angle.y), AngleToInferior(angle.z)); + } + + public static IAnimatorWrapper GetWrapperForParam(this Animator self, AnimatorControllerParameter param, bool prefVanilla = false) + { + if (!self.TryGetComponent(out var builder)) + return AnimationGraphBuilder.DummyWrapper; + switch (builder.GetWrapperRoleByParam(param)) + { + case AnimationGraphBuilder.ParamInWrapper.Both: + if (prefVanilla) + { + return builder.VanillaWrapper; + } + else + { + return builder.WeaponWrapper; + } + case AnimationGraphBuilder.ParamInWrapper.Vanilla: + return builder.VanillaWrapper; + case AnimationGraphBuilder.ParamInWrapper.Weapon: + return builder.WeaponWrapper; + case AnimationGraphBuilder.ParamInWrapper.Attachments: + return builder.AttachmentWrapper; + default: + return AnimationGraphBuilder.DummyWrapper; + } + } + + public static IAnimatorWrapper GetWrapperForParamHash(this Animator self, int nameHash, bool prefVanilla = false) + { + if (!self.TryGetComponent(out var builder)) + return AnimationGraphBuilder.DummyWrapper; + switch (builder.GetWrapperRoleByParamHash(nameHash)) + { + case AnimationGraphBuilder.ParamInWrapper.Both: + if (prefVanilla) + { + return builder.VanillaWrapper; + } + else + { + return builder.WeaponWrapper; + } + case AnimationGraphBuilder.ParamInWrapper.Vanilla: + return builder.VanillaWrapper; + case AnimationGraphBuilder.ParamInWrapper.Weapon: + return builder.WeaponWrapper; + case AnimationGraphBuilder.ParamInWrapper.Attachments: + return builder.AttachmentWrapper; + default: + return AnimationGraphBuilder.DummyWrapper; + } + } + + public static IAnimatorWrapper GetWrapperForParamName(this Animator self, string name, bool prefVanilla = false) + { + if (!self.TryGetComponent(out var builder)) + return AnimationGraphBuilder.DummyWrapper; + switch (builder.GetWrapperRoleByParamName(name)) + { + case AnimationGraphBuilder.ParamInWrapper.Both: + if (prefVanilla) + { + return builder.VanillaWrapper; + } + else + { + return builder.WeaponWrapper; + } + case AnimationGraphBuilder.ParamInWrapper.Vanilla: + return builder.VanillaWrapper; + case AnimationGraphBuilder.ParamInWrapper.Weapon: + return builder.WeaponWrapper; + case AnimationGraphBuilder.ParamInWrapper.Attachments: + return builder.AttachmentWrapper; + default: + return AnimationGraphBuilder.DummyWrapper; + } + } + + public static bool GetWrappedBool(this Animator self, int _propertyHash) + { + if (self) + { + var wrapper = self.GetWrapperForParamHash(_propertyHash); + if (wrapper != null && wrapper.IsValid) + { + return wrapper.GetBool(_propertyHash); + } + return self.GetBool(_propertyHash); + } + return false; + } + + public static int GetWrappedInt(this Animator self, int _propertyHash) + { + if (self) + { + var wrapper = self.GetWrapperForParamHash(_propertyHash); + if (wrapper != null && wrapper.IsValid) + { + return wrapper.GetInteger(_propertyHash); + } + return self.GetInteger(_propertyHash); + } + return 0; + } + + public static float GetWrappedFloat(this Animator self, int _propertyHash) + { + if (self) + { + var wrapper = self.GetWrapperForParamHash(_propertyHash); + if (wrapper != null && wrapper.IsValid) + { + return wrapper.GetFloat(_propertyHash); + } + return self.GetFloat(_propertyHash); + } + return float.NaN; + } + + public static void SetWrappedTrigger(this Animator self, int _propertyHash) + { + if (self) + { + if (self.TryGetComponent(out var builder)) + { + var role = builder.GetWrapperRoleByParamHash(_propertyHash); + switch(role) + { + case AnimationGraphBuilder.ParamInWrapper.Both: + builder.VanillaWrapper.SetTrigger(_propertyHash); + builder.WeaponWrapper.SetTrigger(_propertyHash); + break; + case AnimationGraphBuilder.ParamInWrapper.Vanilla: + builder.VanillaWrapper.SetTrigger(_propertyHash); + break; + case AnimationGraphBuilder.ParamInWrapper.Weapon: + builder.WeaponWrapper.SetTrigger(_propertyHash); + break; + default: + break; + } + builder.SetChildTrigger(_propertyHash); + } + else + { + self.SetTrigger(_propertyHash); + } + } + } + + public static void ResetWrappedTrigger(this Animator self, int _propertyHash) + { + if (self) + { + if (self.TryGetComponent(out var builder)) + { + var role = builder.GetWrapperRoleByParamHash(_propertyHash); + switch (role) + { + case AnimationGraphBuilder.ParamInWrapper.Both: + builder.VanillaWrapper.ResetTrigger(_propertyHash); + builder.WeaponWrapper.ResetTrigger(_propertyHash); + break; + case AnimationGraphBuilder.ParamInWrapper.Vanilla: + builder.VanillaWrapper.ResetTrigger(_propertyHash); + break; + case AnimationGraphBuilder.ParamInWrapper.Weapon: + builder.WeaponWrapper.ResetTrigger(_propertyHash); + break; + default: + break; + } + builder.ResetChildTrigger(_propertyHash); + } + else + { + self.ResetTrigger(_propertyHash); + } + } + } + + public static void SetWrappedBool(this Animator self, int _propertyHash, bool _value) + { + if (self) + { + if (self.TryGetComponent(out var builder)) + { + var role = builder.GetWrapperRoleByParamHash(_propertyHash); + switch (role) + { + case AnimationGraphBuilder.ParamInWrapper.Both: + builder.VanillaWrapper.SetBool(_propertyHash, _value); + builder.WeaponWrapper.SetBool(_propertyHash, _value); + break; + case AnimationGraphBuilder.ParamInWrapper.Vanilla: + builder.VanillaWrapper.SetBool(_propertyHash, _value); + break; + case AnimationGraphBuilder.ParamInWrapper.Weapon: + builder.WeaponWrapper.SetBool(_propertyHash, _value); + break; + default: + break; + } + builder.SetChildBool(_propertyHash, _value); + } + else + { + self.SetBool(_propertyHash, _value); + } + } + } + + public static void SetWrappedInt(this Animator self, int _propertyHash, int _value) + { + if (self) + { + if (self.TryGetComponent(out var builder)) + { + var role = builder.GetWrapperRoleByParamHash(_propertyHash); + switch (role) + { + case AnimationGraphBuilder.ParamInWrapper.Both: + builder.VanillaWrapper.SetInteger(_propertyHash, _value); + builder.WeaponWrapper.SetInteger(_propertyHash, _value); + break; + case AnimationGraphBuilder.ParamInWrapper.Vanilla: + builder.VanillaWrapper.SetInteger(_propertyHash, _value); + break; + case AnimationGraphBuilder.ParamInWrapper.Weapon: + builder.WeaponWrapper.SetInteger(_propertyHash, _value); + break; + default: + break; + } + builder.SetChildInteger(_propertyHash, _value); + } + else + { + self.SetInteger(_propertyHash, _value); + } + } + } + + public static void SetWrappedFloat(this Animator self, int _propertyHash, float _value) + { + if (self) + { + if (self.TryGetComponent(out var builder)) + { + var role = builder.GetWrapperRoleByParamHash(_propertyHash); + switch (role) + { + case AnimationGraphBuilder.ParamInWrapper.Both: + builder.VanillaWrapper.SetFloat(_propertyHash, _value); + builder.WeaponWrapper.SetFloat(_propertyHash, _value); + break; + case AnimationGraphBuilder.ParamInWrapper.Vanilla: + builder.VanillaWrapper.SetFloat(_propertyHash, _value); + break; + case AnimationGraphBuilder.ParamInWrapper.Weapon: + builder.WeaponWrapper.SetFloat(_propertyHash, _value); + break; + default: + break; + } + builder.SetChildFloat(_propertyHash, _value); + } + else + { + self.SetFloat(_propertyHash, _value); + } + } + } + + public static AnimatorControllerParameter[] GetWrappedParameters(this Animator self) + { + if (self) + { + if (self.TryGetComponent(out var builder) && builder.HasWeaponOverride) + { + return builder.Parameters; + } + return self.parameters; + } + return null; + } + + public static IAnimatorWrapper GetItemAnimatorWrapper(this Animator self) + { + if (self.TryGetComponent(out var builder)) + return builder.WeaponWrapper; + return new AnimatorWrapper(self); + } + + public static bool IsVanillaInTransition(this Animator self, int layerIndex) + { + if (self) + { + if (self.TryGetComponent(out var builder)) + { + return builder.VanillaWrapper.IsInTransition(layerIndex); + } + return self.IsInTransition(layerIndex); + } + return false; + } + + public static AnimatorStateInfo GetCurrentVanillaStateInfo(this Animator self, int layerIndex) + { + if (self) + { + if (self.TryGetComponent(out var builder)) + { + return builder.VanillaWrapper.GetCurrentAnimatorStateInfo(layerIndex); + } + return self.GetCurrentAnimatorStateInfo(layerIndex); + } + return default; + } + + public static void SetVanillaLayerWeight(this Animator self, int layerIndex, float weight) + { + if (self) + { + if (self.TryGetComponent(out var builder)) + { + builder.VanillaWrapper.SetLayerWeight(layerIndex, weight); + } + else + { + self.SetLayerWeight(layerIndex, weight); + } + } + } +} \ No newline at end of file diff --git a/KFAttached/RigAdaptors/Utils/KFExtensions.cs.meta b/KFAttached/RigAdaptors/Utils/KFExtensions.cs.meta new file mode 100644 index 0000000..aad325b --- /dev/null +++ b/KFAttached/RigAdaptors/Utils/KFExtensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4347de315a685e4482f8ad79c488d19 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFAttached/RigAdaptors/Utils/QuaternionUtil.cs b/KFAttached/RigAdaptors/Utils/QuaternionUtil.cs new file mode 100644 index 0000000..65aa046 --- /dev/null +++ b/KFAttached/RigAdaptors/Utils/QuaternionUtil.cs @@ -0,0 +1,64 @@ +using UnityEngine; + +/* +Copyright 2016 Max Kaufmann (max.kaufmann@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +public static class QuaternionUtil { + + public static Quaternion AngVelToDeriv(Quaternion Current, Vector3 AngVel) { + var Spin = new Quaternion(AngVel.x, AngVel.y, AngVel.z, 0f); + var Result = Spin * Current; + return new Quaternion(0.5f * Result.x, 0.5f * Result.y, 0.5f * Result.z, 0.5f * Result.w); + } + + public static Vector3 DerivToAngVel(Quaternion Current, Quaternion Deriv) { + var Result = Deriv * Quaternion.Inverse(Current); + return new Vector3(2f * Result.x, 2f * Result.y, 2f * Result.z); + } + + public static Quaternion IntegrateRotation(Quaternion Rotation, Vector3 AngularVelocity, float DeltaTime) { + if (DeltaTime < Mathf.Epsilon) return Rotation; + var Deriv = AngVelToDeriv(Rotation, AngularVelocity); + var Pred = new Vector4( + Rotation.x + Deriv.x * DeltaTime, + Rotation.y + Deriv.y * DeltaTime, + Rotation.z + Deriv.z * DeltaTime, + Rotation.w + Deriv.w * DeltaTime + ).normalized; + return new Quaternion(Pred.x, Pred.y, Pred.z, Pred.w); + } + + public static Quaternion SmoothDamp(Quaternion rot, Quaternion target, ref Quaternion deriv, float time) { + if (Time.deltaTime < Mathf.Epsilon) return rot; + // account for double-cover + var Dot = Quaternion.Dot(rot, target); + var Multi = Dot > 0f ? 1f : -1f; + target.x *= Multi; + target.y *= Multi; + target.z *= Multi; + target.w *= Multi; + // smooth damp (nlerp approx) + var Result = new Vector4( + Mathf.SmoothDamp(rot.x, target.x, ref deriv.x, time), + Mathf.SmoothDamp(rot.y, target.y, ref deriv.y, time), + Mathf.SmoothDamp(rot.z, target.z, ref deriv.z, time), + Mathf.SmoothDamp(rot.w, target.w, ref deriv.w, time) + ).normalized; + + // ensure deriv is tangent + var derivError = Vector4.Project(new Vector4(deriv.x, deriv.y, deriv.z, deriv.w), Result); + deriv.x -= derivError.x; + deriv.y -= derivError.y; + deriv.z -= derivError.z; + deriv.w -= derivError.w; + + return new Quaternion(Result.x, Result.y, Result.z, Result.w); + } +} diff --git a/KFAttached/RigAdaptors/Utils/QuaternionUtil.cs.meta b/KFAttached/RigAdaptors/Utils/QuaternionUtil.cs.meta new file mode 100644 index 0000000..94dcb7c --- /dev/null +++ b/KFAttached/RigAdaptors/Utils/QuaternionUtil.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52358614fb4cc7645abfdec7b22f0dc8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/KFCommonUtilityLib.csproj b/KFCommonUtilityLib.csproj new file mode 100644 index 0000000..465e48b --- /dev/null +++ b/KFCommonUtilityLib.csproj @@ -0,0 +1,718 @@ + + + + + Debug + AnyCPU + {1A3E0DEF-D290-4D3E-BC2D-1B66AB174F47} + Library + Properties + KFCommonUtilityLib + KFCommonUtilityLib + v4.8 + 512 + true + 9.0 + + + true + portable + false + .\ + TRACE;DEBUG;NotEditor + prompt + 4 + true + + + portable + true + .\ + TRACE;NotEditor + prompt + 4 + true + true + + + OnOutputUpdated + + + + ..\0_TFP_Harmony\MonoMod.Utils.dll + False + + + ..\..\7DaysToDie_Data\Managed\mscorlib.dll + False + + + ..\0_TFP_Harmony\0Harmony.dll + False + + + ..\..\7DaysToDie_Data\Managed\Assembly-CSharp.dll + False + + + ..\..\7DaysToDie_Data\Managed\Assembly-CSharp-firstpass.dll + False + + + ..\..\7DaysToDie_Data\Managed\Autodesk.Fbx.dll + False + + + False + .\DOTween.dll + False + + + False + .\GearsAPI.dll + False + + + ..\..\7DaysToDie_Data\Managed\InControl.dll + False + + + ..\..\7DaysToDie_Data\Managed\LogLibrary.dll + False + + + ..\0_TFP_Harmony\Mono.Cecil.dll + False + + + ..\0_TFP_Harmony\Mono.Cecil.Mdb.dll + False + + + ..\0_TFP_Harmony\Mono.Cecil.Pdb.dll + False + + + ..\0_TFP_Harmony\Mono.Cecil.Rocks.dll + False + + + + + + + + + + + False + .\TreeCollections.dll + False + + + ..\..\7DaysToDie_Data\Managed\Unity.Animation.Rigging.dll + False + + + ..\..\7DaysToDie_Data\Managed\Unity.Burst.dll + False + + + ..\..\7DaysToDie_Data\Managed\Unity.Formats.Fbx.Runtime.dll + False + + + ..\..\7DaysToDie_Data\Managed\Unity.Mathematics.dll + False + + + ..\..\7DaysToDie_Data\Managed\Unity.Postprocessing.Runtime.dll + False + + + ..\..\7DaysToDie_Data\Managed\Unity.Profiling.Core.dll + False + + + ..\..\7DaysToDie_Data\Managed\Unity.TextMeshPro.dll + False + + + ..\..\7DaysToDie_Data\Managed\UnityEngine.dll + False + + + ..\..\7DaysToDie_Data\Managed\UnityEngine.AnimationModule.dll + False + + + ..\..\7DaysToDie_Data\Managed\UnityEngine.AudioModule.dll + False + + + ..\..\7DaysToDie_Data\Managed\UnityEngine.CoreModule.dll + False + + + ..\..\7DaysToDie_Data\Managed\UnityEngine.ImageConversionModule.dll + False + + + ..\..\7DaysToDie_Data\Managed\UnityEngine.IMGUIModule.dll + False + + + ..\..\7DaysToDie_Data\Managed\UnityEngine.InputLegacyModule.dll + False + + + ..\..\7DaysToDie_Data\Managed\UnityEngine.ParticleSystemModule.dll + False + + + ..\..\7DaysToDie_Data\Managed\UnityEngine.PhysicsModule.dll + False + + + ..\..\7DaysToDie_Data\Managed\UnityEngine.TextRenderingModule.dll + False + + + ..\..\7DaysToDie_Data\Managed\UnityEngine.UI.dll + False + + + ..\..\7DaysToDie_Data\Managed\UnityEngine.UIModule.dll + False + + + + + + BlendConstraintReverseAdaptor.cs + + + ChainIKConstraintReverseAdaptor.cs + + + DampedTransformReverseAdaptor.cs + + + MultiAimConstraintReverseAdaptor.cs + + + MultiParentConstraintReverseAdaptor.cs + + + MultiPositionConstraintReverseAdaptor.cs + + + MultiReferentialConstraintReverseAdaptor.cs + + + MultiRotationConstraintReverseAdaptor.cs + + + OverrideTransformReverseAdaptor.cs + + + TwistChainConstraintReverseAdaptor.cs + + + TwistCorrectionReverseAdaptor.cs + + + TwoBoneIKConstraintReverseAdaptor.cs + + + + + + AnimationProceduralRecoildAbs.cs + + + AnimationAimRecoilReferences.cs + + + AnimationRandomRecoil.cs + + + AnimationRandomSound.cs + + + AnimationReloadEvents.cs + + + AnimationFiringEvents.cs + + + AnimationSmokeParticle.cs + + + RigWeightOverTime.cs + + + AnimationAimRecoilResetState.cs + + + AnimationCustomReloadState.cs + + + AnimationRandomRecoilState.cs + + + AnimationResetRigWeightState.cs + + + AnimatorRandomSwitch.cs + + + + KFCommonUtilityLib.asmdef + + + ApexWeaponHudControllerBase.cs + + + ChargeUpController.cs + + + RigActivationBinding.cs + + + TransformActivationBinding.cs + + + WeaponColorController.cs + + + WeaponColorControllerBase.cs + + + WeaponLabelController.cs + + + WeaponLabelControllerBase.cs + + + WeaponLabelControllerChargeUp.cs + + + WeaponLabelControllerDevotion.cs + + + WeaponTextProController.cs + + + LeanAudio.cs + + + LeanSmooth.cs + + + LeanTest.cs + + + LeanTween.cs + + + LeanTweenExt.cs + + + LTDescr.cs + + + LTDescrOptional.cs + + + LTSeq.cs + + + AttachmentReference.cs + + + AudioSourceGroup.cs + + + BlendConstraintAdaptor.cs + + + ChainIKConstraintAdaptor.cs + + + DampedTransformAdaptor.cs + + + TwistNode.cs + + + MultiAimConstraintAdaptor.cs + + + MultiParentConstraintAdaptor.cs + + + MultiPositionConstraintAdaptor.cs + + + MultiReferentialConstraintAdaptor.cs + + + MultiRotationConstraintAdaptor.cs + + + OverrideTransformAdaptor.cs + + + RigAdaptorAbs.cs + + + TwistChainConstraintAdaptor.cs + + + TwistCorrectionAdaptor.cs + + + TwoBoneIKConstraintAdaptor.cs + + + RigConverter.cs + + + RigTargets.cs + + + KFExtensions.cs + + + FPSDemoGUI.cs + + + FPSDemoReactivator.cs + + + FPSFireManager.cs + + + MouseLock.cs + + + FPSLightCurves.cs + + + FPSParticleSystemScaler.cs + + + FPSRandomRotateAngle.cs + + + FPSShaderColorGradient.cs + + + FPSShaderFloatCurves.cs + + + MaterialType.cs + + + AnimatorActionIndexDebug.cs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {a32d3424-8454-4b87-9554-ab0734819328} + CustomPlayerActionManager + + + + + + + + + KFAttached + J:\Unity Projects\AnimationPlayground\Assets\ + + + + if exist "$(UnityProjectPath)" ( + echo Unity project found, copying attached scripts... + robocopy "$(ProjectDir)$(AttachedScriptFolder)" "$(UnityProjectPath)$(AttachedScriptFolder)" /MIR || set errorlevel=0 + ) + + + \ No newline at end of file diff --git a/KFCommonUtilityLib.dll b/KFCommonUtilityLib.dll new file mode 100644 index 0000000000000000000000000000000000000000..a4a9a2890dc7a5b63c43609ff52749d85f596893 GIT binary patch literal 721408 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

wK=S6|nMv>Y0CE}Rthe-^yi_&Tp4qQ?=6cH$ zVeMIvCk0VhdydEb++1%HBCI{L-`M@d+kyyd&*8Yo`l~md2y4%bj_TduHU0 zcRCT)o*DVm`!NyLo*7Zh`9xTIX1|agX09c|+B3_0xVe=GYrTv_n0tt@7S2ed`6Ch5 zo*Bt!o+QHBGfPV~&vW8l&2>|`$J?0y`EcDdImuAEV?NK`Inqs=$ZIHhMhvqMk*|n& z%@`u9h?r(?BEwNT%*tmDBC?!_Wu_8YO2js|5-ExK7_)NB-9)+&$#3Qm=|rS}SqdXK zn;#bHBCHCUWr;jPq>x#MNE;##m}7|?oG2nJY<^0_nj}aOb2AZ>NKx|)ky5`1O))dV zBU0~3>yIgd?HMw zzMaU!W`81E)(Wdf%y)>~Ci18`hsaGL(dH>4*~5fYY4ZjVeYhZxnPbC6S}Kvp&5fM6 zEh@&$Ce0SC&F`T-$CyzO!fGzYIuotDtT~qxVO1QYf>|h%X#{x!q>?#?le79Byth>g zq^g<5Ns4v`q&_E;NprK4SmVchF0*JpmeyGhJN=^> z{8TsJP~FrMKx&xN1i^!%m~n&DG;@el0O<)*$84%`E9DW8MHt!Yo2D*EO_0_|qmj9r zlMH44Xgpg7t0v}2(tH9k1f;3yHH1~+ed4r)X66%|xF?o0H+zw0EUYjgQkt8cz04|I ziQd8XDH$2biCY)V&G!PxLtOJ&0NDixEzPx@WN5FTttKI!R_0D3&T-6(Ik`fl3~G>( zHfEH`QqRzq{)qV_$TQ|sL<-<)H5KGpvqJ!3XGA8L-HAN(16COz?aX9BlrFgLFwY&# z`9yBz;bcXSPUZnl(v+T9@2mppYF-gU8=Qy=0_kQtJ|2(Kw6urkqMP|JC!#dgbIsF& zXan&KFuU&bFdK7{qOtSU*x5ck%r>NvEvl#a7AI#t-+U!XzNa~h$O7EgV|CHfoF}Xl z)}ol7o~B{5c+Pr0O%kM+8O=$G@^f>M)(a*C_?HzaH81*!OzR~-k!ksfPxcF!$e8^k zQnq=Q$Tr`{Y|i5m<+B~-)8FhLK)wSRWKIyd@b|$X<`j_&e;*uTen1+T`cU%|(#SqI z)LbMq{ysR&tmKIDk@3829^xcLDKsDV6Oek6St&o$hzQSsj50@a;*JSp&2gN#W5QVT zZPLhilFj!>BjZUnXA6x#o)j~>KyW;%W~G9Rq$nR?-tq@hPcy3&VkARZH4`77VQD~IpSkV%`HDe#Kb8xiqd~-6^-SD&D z{562Q4|34F6F@!#`N@ng&8(&>&ti?jJRdjrJtj!i^O9WRBtt3p4%UmXI&OA(T%?s+ z)T4X@l4FkM#BI-~WXtri_o*8pjZ@}It`RLN3s$GheF5YL@3Et^jDMt0*%|g|f2EPJ>XD07K^Se1EPLQ>j?fAaHO2J%IQ;-Suac=_T4|Dg^ zg6zb5>kUBen#uJT!PN@y?7sw(&-YG!M%;YqzJ;7*C^2u~6vI)NWBa}fAj4s0_>>0B zDnl6y%_tDBZ%P0e2jcTZH{_m`q~EdcRUW(Oz7d?bXVW>pPdIV=pyOM_Nrp1Cp{RGq zcbmww<1u2vv*U9biPYaUJ^W3s0={G-iI{z{ce@Jt3N;p*S6|0-#IP#tn@8kKGh96| zt1jk?Ya%qy9aWUs&=mJwBeDWy0Z2(-p{7Dpe<1og$Robd%>-#W65|rcH7J=!2V$NHRBlnbQ(J4iKOY->TzAgAnoqB!42L{dR+L-Ukx zSpW&clPEQO5p9H(@h;j0NKM}=PTclW+m{&6G+BxVBLEv$Yx`QZXCy_rI7gDjoVfK~ z+qZ_345i33cuEB_|h9_1O31Yfz{BK0F!Mh*mN=UY$Y1m;L%Ksx*4`Us8w z8Ab_^ZoWhP1bOghTo^%m`|c5`f|kj~gg(A9{e|Wnu3v0K>f@_Uqy<_yBYl01h;${= z&)1g7Q;U(`e3+&95{bl>^(c#x)&O6BBF8Y2u(SsF4iWL}MH|E@I>47p4VR)y6- zU-SSG&#@7>*AFtt7f*zpYO)n%urHfP*KW8=1v11}X`rxbiWSFqAj5pxAVCIU_Wl#d zaNleq%TdFOjP%6~7MjTMD4X~3-mGs9k)JTOF!Gvj6%iG)g0rwn_B}a_S-JI|=EGO~ z%kt&xC-$iQB=YC!NVyQk9bY$Ym7&P7cf2o&$V}a%T!!cIzS!X+p0`2Rnci>tl8B5Y zGSRn=$RZ+>eER|j>)mhrZV+L!IOb=vPa6>&^AukxL9|WJdib?+iZ6l4cSO>C6NuE_ zDz269`qmR^MP#b)5|J|4>0;O1X};)@JT0vzk@tKZILS~RpMu>NE zf@t4=ijqfvU+Ys|=bp8tcyEH;b6M-th*W}SK^!8rKq3*xTHkCU+mRO2eC^95(wh3k z*S<4E7GbwXXs&W1p6Hm2e0}YU8Yl8qwiS9d#^=pG^9?~BA+p7%qzUr*7Ss%^w)##H z*@}2-Af9bL&v>DExijvaBB$GY4{(y9^}u|e&Fiv!QA9?9uz6jUFIo_#?0L}+xBF@k ziSm_7Wri4;f7>}r18*Plov2-BSKO(ViuR9QI4 z@#PTN4nIG`^C{mQPNpjC?ciTQe)i?P!_soc%yYiFlQ~gFH5cW4&NqdV3}tvZkMaks z&iTxDg{Bo+!CjDC-vUlDl;3f^V0r(=x1ER_SAX>#Ai{o?CSn10q?2_1z#M)4J=s`jOB`&-Z-xEJ0-IidBUZH!Y7Y0wK{;r!s7#0mLS^xw{b;#0ILaWZ-9o)atm8O z+((YzM{+sIP^RC;?g1h!Y_t{BCn;LLZ^iYZxV1(Q|4DtttlX?l&zdf7xOAgw<^^)1)ii ze#5g8SaX-KrgM^_oPdVyl$NrhmIyzG8jI9RSxH2GttWOkOIbNY=8@)MD||V#N>v{D z8dp8k#lx1yiQ5t$wR&;lj@XY{$(*Dp`Cb)Pk6K5`Pi5?#z6d|1t$Re85qZpdWCcsh z_58RM$BBC){o~eXBJ!;JGS;RLtFl%$CwTq`>jF0CFKhik)=FTaObN3o-^I z)~ZWnSq#n_1gUNfCL({^;wdYM2>YcwHgkB&nn0xaHF$mtZPC(JvDDL*bAO2IPEE@u zGP#K)g^8^3lM+NegCBOas%b@YlA-)E5Wii3cxqaeNb?<5NgsmLwpM+~(!!I33783j z)U`Gc*^If(W{`T;CL)V)2VoCLLu=Vr%xbFg9a<%exsg?AwIFXHWkwoXi#W+po*jf4 z3apw~nMAH5o}-*>C$fo1Q|kcvxs53$^V7`gvR0HvF8UWc&8E4vYMmg>J`|dkR`z;9 zPHw_J6Fj%FV!sh&F80tafV8pZ5{X2~UjvD^t`aFy3(pZP#HeJwxItKT0kJ{aThocu z1}O^C(aI&le%Ue_q>EKU?zQeed* z9ANd&62!sGoR#w+>yhn(G)fd?uoX+BG_2U~aSX905E&0mJYpVdWfNiNV)Xz?vYc$; zN1i@3${MpnkaJk;v6Hf1v)(7t?G>!}VKv5DM&uck5BnXlvDPLc^7l%Tt#LbrpOc@8 zT%=gj_Xx6rNUHVOK0!>h1a>Ox8`e4^WkHfb##=jxOx%oF9$Lbi)&U}2L0I{`WgXZr z{QPzV-(WS#dg41l9ITr@1bN45ON5=gG#_M&l}hCCTX>EJIepifK_mfW6*SYVT|{03 z*$9$h{Y)eW&rt0EnQmPrGJ*2-fmP}Uk$N&_!mPe#SQ$SG@;O@FK3L7PJ|&V(%rvW^m|u|xRz*vca^p2%#g<00XBAzCJ@i%+c4M7}_TEcH27sh@-SDf?c~ocyVXb!- zeimAJM3Vc6cotdvjtPx%Pxx7EX(t4cr?D-u5^@CTQbqLBrPfO)1^E=$i}Ucj+?q)w z1%#!((pqpzXlAU#TppS)t(8Q&6Zy(oPh>v`E1%Vtc3M~&MAleyh{$WfT5AE3iF7Sk zYpo*E?z-^vwe`js;U@{?4pLud%_CADdk!qZ4OT*~&~zuV$y)ZCAi2l|i)V{uwJy^5d znn`2<`a4T~yR|4plWiqjcKsAV>e*K8m0&+Rt!YF?;gpQ>(CoBIT@BXkvAPhEG4HW* zh%~0wve%k)O;{}jVQGD9#r+|OynjPq$lxxF^fB5jgtiL`PP8ui1pY_W_41pgf)J1 zPAUlEnbAVb7>`&_l4hu1Q=1bJGfV4;)sn1aT1Tx8l2BSltxC6o(>iL!3F1%ds8xqF zGOeRl6HeT;j#}-=N~U$p>MaSSbzHM5;-+=XDke1k zGCXcYOG0TKx60fNPV2Z;SrC6($E`Th$h3}Ibvbdh@lC5=q$gjI?YkrrD8oUmd72&=&pR(0|tQ_ry)Nw~jl4uGx4M7^kNRmXPVr>d(a#A|Ls4VdfK>e*RocAhN@siwIR{V*I&CCQ{j-i##Hc{#?AI zF{{8_4CW+NsainB?C8RCz7mowBeL0_i%N#jeCE%^G9tJ9xv1n7nlJsiSVp8^b?Ld1 zDKu~RbFqv_Z+|XI`GlsHKNp{H5}1ocq?zh(QROUQRodU8Mic4d&&2^Eef_y8XA7$X z{#=YBGRL2bqeK*cE@B;F)y)B62K2#M9~QH=|GaiF`WU zCG6?+cw7rklSY(=YGSS8w_@*Bu-1FdPoy80Fh3pP=NGF|ewGV&ZT_oOixan;f3+HN zlB(3rCp`aZH71g-O42mIij6J5TJ1S;uSCCDy(OWst%9DiB%Cm9`vb0i^hf9l?^Q=3ZoYX(*;87A$8hKVk zAs&xE^*qZfh%QslvkH-BM*-|qaI5x2x)k*A-<8g@x^d!`YM#}P6Sq|JtYMs_Dsf?0 z4{<+l5Q)(QId8pBgf%0kxnRvDvg84*kU%b4yEt(@U$PF6CJw!TX)alXA7J@%HNRUA zagwU^AU*Z)>Z2&S;@4nSxOO6 z?}?PwHS3Nb{(N1tB8m!)OzWEE6~x~*u2}^+am)FdRh*Mlr3J=S_De(8tfxXWe^~WM zQ|fw6GfUE)?HwYK8S9w5k!m36>mwHcK0Y=8d^aR_LQk<_Z5WaVil}>_5{)-pA%M&{c(V1BQ%b^ zDS+$*DQIU4qKtW2oOM>%K22l>$U$g|*a;7by4ZlHaM^ii#q5ZZf~;SLdwS43Xt(18 zzb*lC4kXGRCNw-kR;mx#uXEy-YDs&NBvh&;?bfA&OSPokP7r^ombAN)MwV(x`vp!! zsa`?qCG8|Zl&@*!@`yb(K=UUwkJxKSQ{oGh`eN)Y+vOe>`PzxK6+2V6j2%zp_&Ah2 z$P@N(PVl=z7}blys;oVclan4f&X={Pa^m){vi8TqkN=&Tvi298q$-hy=qY9Gr6HPf z_G;3cz#Q^nq*cy75TGdwQrRuT9qa4q*t}i5ixcP z5^I}}GEItho%+s`c1t1#b_MFe^ON>#oQQI6!pS^Al=e%-)icf>9xc*JJC7&9p^39| zh(rz(Pv+OKb4v?NA+oAzuaDt`mrrL{)wG`|!^l}(KJoIj9m|PG{Y7Y=w#NyLM?M2n z&;F?_vvNzmzI}!hVZ}YdRi4EI zLOrFq9aDi3ciz(6Zpeu{Z)t9~6vW?mn%iwjBl}Ksy9;ULyrsGQF%j9Go7-P-BJ$26 zY;I?gMqVph*k;Ax2wT{NDg{T_!mh-L8(|AOP7r^DE$lj^krB4Ao03LG*utJjL`K-c zp2~?EVGDa1X=H>g?HiI%8Md^QD!~!9w4*q2BW!6$3*wKkrCpXZGQyU2ENNtfE$xv+ zWP~m4v7Dr7#eNgxb4z;)k;0#1#}R=bLP2;hcpGh_rQM|}i!e=@_^s$)ZR|gZ^n)MP z#@g7?u}tH(!!~v$PTV%%#*X78RVj&?`ONOjs&$Aa-fnjvd7i9RU{%ZR2FBY%ghtzv zDDG*-+hd7L!kd!pd7F595|Jr*o~`#FMm`|&1@`?WV^tP!e@;Zl7$wL`BF*dL?g6*j zMC4>$>?m@whe)T=9%U3KhXvs!HXS7vZ-+g}ON^7xK-$`M1yN=V5GB^mu29X@u=d=} zuFZ+t$jC8W|LaaL5S4lI-#=bH%o$aVNH}5R< zE_O60*nuHU7rR}ErmOutX|7`RxE_AG+G!!0=k0e$W5Lf>Xr8yf3ej}4H;|@Texd1R zpAFF@+LuVv9)5PhPof=OgT?HYPj}nq#BJf-?IN6{D&;V)?uS)(`#~ai3JcQHE)nAA z1-nd$pBL=PWYq{gB|p~iFW9jmnwRWaq?w9+k{_}1f60#L#C=D;x7|TlX&+-QF&8W3 z-gbA=$n$Ob*nLRzAWpn#G89k7+CxbrPrT`Cze<|5{c!bwrmvk!8hHjzKYJo+3a=4Y z^M3X;L3l4%W&+76dsKK^QM4tOJ*v`+1 zTRVg85}dfTGuST8Nh*HR0(WLnJA>`2M2?`G85wHVBhnd~+aSa3)|UI>@ub;VDGCB_O0Hu=Mfo(UB?F4x0+}#C*r~1htfgnxM_( zuZ^dI?MxzH6vXp~Poodpg=(|%Nmafsk0P%m@365I-N-D?|KzV6P*qUgYNkdjpaF4+=js z?Cl|bKC-_L@$->=gsjrh5?bK)$w&5SBG01+zXbW%&I_^n#J)IB`qkQ#+b8<#Bawj~e{cULK;EYp*BG4@heRuCjCOf_0c@*Ux8m z6erkyf}iWqd}enf@&{(ZOECU?ZjTJH`oc~o&1j5=4>iD3%J#_+%{==T(u{|u4K(v? zPu<|u=i4SHn57`6Of%oEAEH@cHz!RJ;%SZ^x4`ZYqFHDslBP2GS!id3XcpPCNb?r? zS!6E?(JZ!CktPCuwjrLy_Sq2468i#azCx+qhGvQFsTZ8DrMAvVs?q?ZTCpLXyS4L& zXqMSgq}fSnEweL2G|TPXq)CP!7SD3KZT;Z1R@j|6NmUA92akR;I=C#lMt6yaC);t-;-u0%9*u|wRT>J=4<;ZX?jrVU)x~~gCksL8=RynOw$rqh;?>> z5Y2i!iZnS$iwv)LX-noii|V{?+t_M{Na7JC|L4k6}-7^Jt@Ux#S6 z+FMAIN1Cm6Zipt+zC@ZoQ9euHC)18;931mDyAmg<%6`-`OKY1wB}9{DPbZBBewZf9 z-VmbMZfB9^LDFou^FlP)_EpjpM)|OKvhDaLES^;57fOAHJ(v@BtlMcPk!CJh9ZP+u z{Yi*smpz{}uOfAJp2aSEZ-{2MeTX!jNweE7(KNU;_SmI4NmV{ZJeN!1tQfm$h-R-{ zi!|rZT0U!vr}ypT5Y4yt1k&_IYk3dj{I~WLB2Fbd^@%I-K6?(4&QIbUR*?PnQX)lR zaR%4!@9fn?uHo-hYvH*9dk2xhxWYKNE+4Rua^jZQLHjgmI#$7IV+i&KZBMh{oc>^& zoTMs$P%eJ3M}%m8w3A8G4E4ow`lG!uM03c_Ce6<@A|0|HZ62J~Pj*>OQkCUstIe0- z9R#~}h~}`}lr-&;7VD>n?Nda4M7^`ta>V{M#OkPhnKXUK>Zo0@1+^%$I%Zer#4VrW zc3skZj(8Ff&vAQWh~|WyO`7>=E$mu(!d~1eIA1yTmz<>HX%7)$j{OZ08>zGR8BW^U zLaa{Ndq^Ya5~u9rA)24jcc1zr^B#k(U zt`GeD<|piK>8l_Y?(=ieuVHsx+4)hw`w6@2Iv!S+{Y0KEcI`ettPimWMLaFr;PfFs zVSc8<&n-WZe*U!E@SM7}bIzkY!&yNj2gG;=dr8hZBAwv%B8cu} z68RD9g7{}~SIpT%q(K!tu?S*12RU(bVL8W0GXtf7flaZTYxilCc+q;>pv|*7wVYK% zDkAlBs2$r;o)MZBNWCDQRCb(}oVaP_cM?d`xRQ7$J-@U1KFuc5EUPNg%I}0f%RIY& z3OHU)Qk5|%!$$a90Vn1@O(oJCMX9ow3plevGzFb`q^XHfo%t!~c-jW1RnRdxNmb@z z9Akb8It@cKg`Ae8>4%vE^Ha#_bDw57X;zV+Le7Q|%>zyrX-1Ks2b>G{X>O3FA?l08 z^MDhbAWFUzm1Qc*$^fC6mzmetcp4NND~Vy3;m*)Q|vhr;bf%sP7>~RIS+H7h_-g%C!WQ66NUPNSs<(*ocf+H;NG`)``a1!Xb3n!^c2cI}kro8idh^B(`7HO8D z@35FFICD60W3K2d39+i^d_`6pQKa)w8Wo*GM0$o}9@-UqWX>rfx3Isu44TT$MIv`f z3sS|oL!?p#L8>}>=ir>iIuCH-<}21I!AYue8B&&3tn+w)CK7e|q*IR*cb-tq=^_cu z6RJ74yRfuQ>fJC;n24NIbHclF;@_XI<`{zb_vfoQg-G)Tp4(ZCd{uJ>5s~wRYR*Vb z+?cC5V>wAxwm4XgajR*ZWN1~81NP=`b!P^VdLZo0-|Eh%oTO{vxDUWIan1rF4}dUD zoU=+0|NEX#Ime%8xyVok^~Eo*^}-uHPDD3BNuM@!R`U_wH^7Y;~WUl)OC)MX0?TxJ2Z8jn*kbDU-g`V zJ(y>=zUn*WB%%7M@9ba`!+`p#@9Y=EUtjf|L!^=Oy82EIX=HuXcPjQ0Y03Jk?^NeR zGC4V*aA$aoq!Q;EoU8aOjJ zarYO1`qnhy3%=wMT7F<)9pXSaLBH6fJuy|THe-iluvpD9b zrK7&YN-R||@&7EIR*sKIe_VH%pVrO;oVa;!<2=lXoA)+O8M4}d9&iO#ZJcUEjujQ; z8K)_cl8+10)_Fmaih?}n3?)(uS5M}ry)%wTIId`nbac{*Oh(=r>Fg{aatC>5q^q-z z6F25=&UQ}Rn7cXOlGP7rU=JYw-JFX=R-(QbNpzgvqI`y-zHY;Fcc&4NRTVIsUWzNR z^Aaa+T0Na%oVaQAbViZYHtg!_uTdpni-uzZ0~-|6i{_hrO=8lksSmlO9+dT*zx zApYLe+i61@*_(Ph9Y`bZr1y4a5Rtv9xAQ3{qI_6{y`4>@k-fW*Q>b5XgngXY{=pIU zapE~~BkbdJ5X2v0AEz5>WQ2X3-lUNc_Hh;xkrDQBR&wG-*vHvN8W~|UwP zz~Bh`I?!OjRy+a*Dy8C(Q z!9xEmPB#nGOFxS-V+iEyqJ_RDw{z1SUrz8aywMb>pH*4#h_1n$Js-y6e0MMVbp0G& zBKXgErX-N>`9<(h{WJJQFQ${9`P;GYVahKVOdqZ^y30OMF5sTO!B^uHEcSP8sL+Le zR>AKEJ5HEVW-i+q2v=VDlzm1hEm1j+6REuVHv67WsalqOSCw$2<2ag9cMs#ba`^}L zX(*rLy=}+wD!)F&K22r+EyjJyjNJcVSh=L~&v2#mW#-o{w_2D3v%f1}3jSB$e>lVb9i$uFo$T0IzRdpbea>GcbfUdOzgv74Jj`$ZkA3$j(qB4G_hR|I{3r7luDrNG_??EQ zMp<0)Q|LTO${qIiFl8YBl=;T|`VGPR9AclL-^1~ax$qaPlRQEhIYHRH!SflWNI${f zrQW0bZSMLBPUpWLPoMvxc%&cMPGtQ>b{F}TTzrNp+v7wz1#>yh;R$ZC3-z-;?Qi+> zQ2YFAzcL-!9%UR^wSxVHrYFkRE!WWc72m@{>ea0`sh9N_s{cp*%kmX|{=R>y56zGG z?)D>5&hGbr_3yG=kH?Gp4NZSYO~L=wcKd(*h?V1CxA)L;5B>gs{Ydot;C>m}ufmo8 zt^KG#vWP#lUd4B}KmYCi9Xh`LyY->zx!>iu{I}a{GDv?uy@rVxJve6rX8> z|27xbw=ln6ewXDH>PPwuP~b|6xAc2MJStdtaot=A1}R`1dH{yZj7O=F|F8>csbOMe29_ChVnd1$`Ikgew}J z*J9-=(_7E?qddx-ae~i$O?;*f6Q7%KN)F4v*hdIg-sk%}5sLRs7I&ml5IdA?-{?Hw z$HQ;k{x8zAeXQNscVhck2dRAjJMsO$VgK=SEWU`pEWdx`@2o!mm3*=Ny>iR``}G}K zKK~9sa^C+v*4M26UH(zT$-c98dFwbUKbJ?*K5{?m&*IY^AO4Du=i@!jq@;2GwGv{y z@$C}n$=)%TgU0HZb}cgOSpb^rhAa_do%jeFtB{sh+EBdGto?ey>c z{Xf+X#P}ahj_}X3yU;u#w0-@jx$F-jF1Ovuxc=VX|6Tcs{_J@7a zknj0$dOW+H&RWR+9`4uuPxH_E3;%_-u}_a8{r{(UgYtp#L?|!u=MVn#as8*tK8Jde@6ErjhAvCVP_soCwL!$rTdTQ*m^;% z>s9}{{-3d9`vP*^`&agC{mtU~9_t-8KFRs?2Y1DH!QFXws7`$MDF3zI^)L6IYSa2P zcwHI1eqtwO)QX?kI=DonT%^w zB3q}0`Qu(m&;N+eFeQ@KeWBk&^T+(KeE)Ot;|%$r{QvX$k^6|EzTABV`8|^F`-S`W zCs%A?(KhYJ5H!$fA2Y(eagQ_DB1BMzyI~$BbA1YnSYP+kLmI$3l0l? zWOw!%ro?$gI)CqZCi!={Z|K4AGO~1KdB`~AeoJk>uNbCG=KB~PMSS-t(_0HWnZ9iQ zzhsHHWVwjHdz4td|02sPOgX@>|NrSH-QQ>J+uCcdz4qFd=Q+Qc{@zto?oZQ?Mo+G9{b!sD znEBeV{U?57vL7`XeYAD{^*JP$pRU74OV8ye))BIAB=z!sO=3TZ%Soh9=J(&%Bl`sj zyC?Ph{Jw+iuSk6o{~QcNBB%m|6A#!mH%7mzqQ`c(*M?aM@v6i`M;Gu zTKT_~{y$ysXyuQ_=Wk8_OXDb64@ax_|4cbDPI*6->^Zkr!vEZOm33(HzK*niw0M!j zXz|iNqs9NH%Kx?fCj9(wNiXtC=I8%5KL5M>VE^6x|6BL7q#yrN{KST4?_9SWvV-zW`RQ5m z$+N5RGj?dY&+R|H(ZL>G?F>(dhvx9fPKEn%FZ^rS{>pA`r z?>(6py!#3gPP?At*AE@_p?A(I;a6s#8ozP-9|&o^dAC%@LZ{QA$XO(*BS64sdYC4OD~Gp>)HUDf8jfAw4MFD1Vx zGul0>mEOLb+_#Zu2}i5gsIPv&G(hqu3tw?0WCxX~oZu8a{=~<9lU4eZTCO(>Y#3es9ZB2T$Yj z*ME;IQLm)aC#;`N(*Jyjdr}QlpQ{R&&^Y#~9lY@<d$h(|ziUN**6S zAD@_aMw=&pE8iC%!}YNr>Zm7g=YEs-W_W%|yjLmX`nQJ5y?e*%?@&DMfmbkJecpMEgvopeT|$ZHd*fQ&@78Q`6^Li(-PbKG0=hkt(5=uSv9yam2zh@tWPVZO$9G&#!=jdq8}ItA-TJ1 zPZRoV|42E>{EX>d}-sS zt-DT=@Jk1Wl=6gMrYHP5ejZ)lq`rO4cN848iFbdQ`%C1L zs9(m1)Vs%Z+z(%R>jkDK=3RLfKS=U@W7aLM-A5Arko3|%p(o2j{6$G8<+4A^{kg8* zN<61e=&8`99a7#V-g=eg#Q3bw# zLjBABy{jJd)^+RCwc=-4N3xvP)i04#vVKWFOZ>Xe|1LkZYu$K}mz4jXh$s1o{MHSr zUcH`PC7z`n(x2y5_$O85uD=lY@J zt;Z7liXKWjsdu#YCex)|+-~jJjf7mdyo8LN) z;@EZaxhL@RvF08;);p`|8Sk-#*dB@;r2Xqw!ah>9}8u?^fZKnF@I6czxigo4oz^V-4L=e@S|N zu$Ri$D!JSiV;;O#Po}7pb@J1Dw$0u+|1J5*t|ZSF!Z&}Xz_t6G z$^0eflX}<9N9Qlee61T#^-I4h|kNzFIY( z!uJ1*E9u!)t4x?oPdv;1lgu-{UV3?!{K?N!&%zG89<`g}eKwxU zbL=zMlXzyn63<+(qsE(k7p%we6>hqpFZD71j^cK@Uc0s8_WXJ}xBI8*g}>zTr5(w1 zY5%XK&oTP)(|V=dzqXvw_)nIn$V=oWa*}5$N1mnq@+|F^XKAlIOMB#5+VPWTqeref z-qR;pHyxQox8*0%Ih|wk)3{hyzolNzpU~U9lXzUPf8nYFaDRmCMepf6ZvJ)^>6fD@ zp7v9dK@|dPt;(a!LwDP8# z^_x}_j+QQ&&hphts`;D%k$ITx>ugNt0^7)VsD;XpPumlj|;N?P)K?>!+Q>0%k?ZV^=Xy-%-jbDjghc8P1@1Jph!@Td9NO$mD;vc^fy(`!E^X2pT3Z+Yq z?>6(8quRXrOzKZgCwjo~iSOgd^X@Yf@+Cd}?iuDw;#sc3x1-LEQF>SX$%I`p<>l_=uM!n%Cz5AzxVcwe{DK$pQ9#t=S#`Y&wKYmPWJX2 zV)za=$tzioa-S_(ZX(y|-g;s3eCB&Jx{R0I&ANYd{TI1j>)m@=|9wIIlkd{}Z;zLD z{JIb)4~tojlK#KjKKb6zq(biB!Go!MeE-YSGkMNw-&qcFzW@KVFktl4QBS`^ za=_$S z-;>{{)x&?M5a%!^bX5)RlaN1o*Y9{dJnzLb-L>@Oe2>1t zbB0i;0Yan-$pV05~_8I=G<%=G0zqpFNFDT_3Jwy9w zT}Sm(|5rW7@&DEO_!%jLeZl0rvynR(w;FPqS(#^Qb#?f0MIz3*^Z zl>7Nd@BXvcTcIC@^)2;F?&TEvR6`!y?W>0A8Q)1gfSz6T>5=s8Q%{-uCn@R&v+nV$ zA3T3q&c%MIT!~NS=eO3E+zu&E%KuNdYyEpx@_vcjyGq>4lluRs_(|5MUwXd9^l#$4 zgXQ9Q{q3r0xUWk085ZNbg!C*qp7i0D;z=)Zpl76aQV#VG?Q8PBBFl%K|9U6a6Eow{ zQP-M%H&>nIt(z_~@!0<}>ls(Q*~jTmGkOSnW&9uPXPD5Z&NF(e)e+vlDDgr1%I)xZ z?M$(H&HAfVKF-C=NU5UoU3C!3qj9_Osr0PXquzZ%)_Z(E-qfGa|MO0w{C@SMx!0Sj z?w`u}ew!YrDlRABl@qk(%uQwfO0oY*_m&Rz_CeSFmFtmkAG1&D*!Cqq^FEOF?j1Xd zzeA#x?2F5N+2rR-&Hja>{N^5#Yws<~`L*PeeWqiL{_yYYkUoqSFZ6rNzMG>YU&D*k zE}wbNfzA^oo$xRBMtMGw{VoX|Rb}Rv(Vy2ZFLB;1V`WgOjDt?6o%FL#=fVk8@D6BBBHXlqA)`h8h;~GWnkYXGc&6C-y}WGQfEOgGc&W* ze9X6*nK9)vzh5*)y#>B9Gsl{K&CDF9xSzF2PwlvTdun$=j)xjOzBG3+rq1jCk|i;}r9|Of-)2%>HDm+TOG)p#CIvH4SK|AY z2|FwHKRHaPB6;CE6%lU79j9@aX2uipoAqeoyVa6T-gi6(`?J(@?i9a;vBO&Jbpi3~sFPo#5Por-(mCqADV#p} zna7W#u78%(%kzNQCv}tPa=*q=A9&|Wl3vP}XO4Gmz3bbjgkH1#aXtH^?eCe19g$G< zTtb;|w>W_KcGQi=PZoXgsm+Ioo}$K_NTFZ-!`wekRTmyc^1}DM%{bwZEzjOa{@+U9z}O%73En&=lkTU_A}@|l=$$-E zKH*R3QvMa5ADe6T`+Ta=?APJ@#NIws)jZZCzK?}{V>7-THFh=0S*xKvISdtZm^PC_ z^pEFXoB+E>^UEvmQ7FF?<|xtwnqOyo>mK1#+LL@vEccM)ym*ecPI`K8E;l*7q?3G7 ze)9dV!c~+%MSX47uYUE?S--A4K2J{E4`Mx$bL0d)Ii2j&&^~n>~B+suwTkFYX)MzT{{5{Wb}I={+L3zxQk3 zt7LoWsC?+ly7$4?rIY=ad#DxOK9t-~mV1G6-%!pGANAyyi}{&K{?|v;KG&XWPh7<9 z6?=54nU7pm>gk>MIa02KCwu1s5(=He#CvE$m;1}Y=lWsdo+ICf^eMg%nPT4q`1$;a zd#oaFPABjC$-Qhx6`KBb)g|V;UbxS73b#9%U%sy+_eSO3@o4q@@_Ta9{^WYrr)%3z zX~#FKh`;rJuaU+f{az#4Z~47OzNej#pWM$*u21eUNw|Ldr5(xrmUyQ0v`!NJ6F%2} z{%JXn!~U6JkK-9eEhUtk+0mpN)9Dn!k?E%Vm-3c zQj)vqLn4&?946$&@5KmTqlJm|%IIf8?~=-{M|?9V3Ncc$MHCH|Ak{rP7} z_iIB(1gn>#QQqQ{7SuPUcTgbo_FwGs+o6OJMW0ymG{|_pD%3Ue)_fHuRS;V zwds=Uy?+Om`>zd?^UJgR&f{p|1q0k}IUi>~UDlI{`${qoi@zg&qlD~F!C#(De7p9& zFX3afa^>D*iMf~Rsv{OKKT@v5^S#wX{Al#i>REprJL(~CUqt9ZW7owVYL)!_Tidb8 z`P>e9ukw`#=o#`f^B=x@;EgM$fnBm^4E`-?`$SQ+28xb+h?5oGUrbYPr*I~*+sdZQD^QE{`C1i<40pZ$M_G4@4SkB z|57NwPtECE<=(^f%K62f9v{ii&E7gA`FE`O_q4I!n@#25J+`;Gy!+EgU$B4q3_r{L z8aW^35Z}p6vKPXitm~4?7k;Ij_c!Ev4)pHjB>(QW@O76b_vGLCzR2uLVP-dWMyneN znBQ@eDRk6nd$QgO|8m|h{B1Xl(@8sjDL(o4zJ)(2e{)a2B$VHiNe)Hdg)aIOn8^IU zWbUD19!z?c^m0DR^2YB#cXB=nOWOEZLZR>P(dAj|dDsAwPXi&c}L@s6SaBZpkA)95u`1N9>l^p=7^+@0CD)-hLk6L;30bo#cEx?i2S! zep|l8?;VN#;NL%z@51_ia({^LP2hgFXYZul60X00>8M-H{)foPQJZ<|Kj|-yPtcR? z$6a22kq_VBzmj#CE73C!@m*q%PdQH>Z|sIv9AaPDvy;NF*eT&x+Pz^P z>m!Gl2liq6MCa$EAFp`({9+GeTuGQb-h?ip*#G2E;zi$NoF>mVv@c40(7q`7C$uk0 z`%1Dey6ghH24=n@KD!uWl}r=yf-U;a-&A7akO zw31NtMD$<$2Y$~T-vLSTn{*zGjL((^y^Aw&3Hc-_n2Y(ylZ(}t_ZK_&z zDZ=S$*f~Uf?;Hud0JOW*SoMr5)Pw4FcL=FJRrk7|BK()yNPVkzQft+&Dx~-DMf6l( z6k!(r#^_4l2Kd_$f4k_FzC!%%iobGQpr_;S5balo=t6`O^`XFr0v`%o0bBuG0XzeE z2Jj5v!+;M1J`DIs;3I*L1U?Sn+tidK)#Y_r%|zGpu(5Di;Qs?Ox49Jwx)cMwp8K}2h?DDI=!a?r{QqI!E0$Z$V{Xa>y!irIQ6 zs56mw0cgD`g#K#NEdpxvOM6=lx&gEP)whqog*BuK@I?B;x z)3w-i4Ph#UUTbbNi0T+Ih>kvj=@d&cZBr|%l%i>`O>KLWQu_n7+TQ9=hyM|)FVH&F zF4${60cfeEEw!``H4Q6vdRcR+MXhS*cBL)_tvCH2d*jRts80o|xVAo3>eaT=)Jq(! zw6p##?Q>2Ez+Okd{FCg?qYh`$LoU4QyF@UZ4ON)4)A>d;D{;qva`So}Ru;sXKv2 z(r+u!svRh(FT~m7BPR9;#6D-x$Qh6hkdCBeEA_fbM?JIBpa+gpY5*ut7oDlpX9mrv z)aqLx9T`(3Ip}SGA3!V6Py8Jt!XCd0MI&dnL2rTL`b6BbA(XEtKx7ku zaw1nx!@ez0Zsc-!8C#ij2cSy}fNJ&f7NvHyvD1JWf>)Jk^=F_0?SqOO4;0rM&61Lr zz=t{+v|%;*7>o~~_P|r$A~jGn()of?^+5G{Gn@etY7ZQMI+%70?nC?)w7A;|bzNjo zdt6GMf*gMXEnlAvdvG&Qg|Qnn7Ao{py-M8&T0!KqL-5PKK!uTqmNPBtjKPiJM?q`W zlTgZ2KvCy;oPIqIRH6sbt1kmh)*|Q0wl9k!kD%oDO^#Mb{9~Zj)WCjP4FeTK&cvGU zYoLekS(IEGhZaAwjOE zIXd!~SKF|nn+vxhM_J0$7U(WePGkx6fO>j`&YBA?Hs#&2J(rTFkH$MTq{YMfv#*s} zj#wV&uL9LYZiXJb1vIRuJg3wuph0Wpd-RVrkR)h5`Y$Iyl0fy5h$pLtAhrAp&>DhG zsP|i-sWxwGs`PJb>T6hiY=UXBKmF`al-dTUSc@$#)iN(k)i1!XPc!LO&%xO~P`N2@ z4p6R{A)uCt*>%e8Y}(9UI* zRy!+Adp|-cvut~3X_*@tBEpf7#=0~fXah0rp_0Fr%h$v|F&gp&VZ=go!TF{Jk z>ic0qHa4*X80V-0cI@ey%xOb#0d8clZKvMa8tGb7`yq`TfQI!$TWM3uuwIRu(7!jd zH-=$Ff%<(n{isx_L6>@{HC16;Qr>F4J<^ec=2q}3e;eSSFG*!i0Dr5!ZX(W2BpfO^xH z!zMm$(w+1G?1n)NKCNB@YIi0!D)lx{r$O%l!CM6FQ=qQM;&Z^WNp~}L9I2IECN`Xk zu@G5{F|z?sr}G?a#MVH)ktLAE4nV{DJ)qr8Y|W$4bf9*J#s`(s6QQ0d1+6C%glAM? z5XBw~G;B3z*ijg@l%po)3&@XVh+(bqwhhzn6PnQtq76Hf$K$)tD1}G&89)nce?%Se zcz874Y+|L47HAm(3#=sjBdZ}l^f&(Q#cm+wSZI4;q0#3zKwD(>d6CuUg;paLS`Ml$ znrBgK>OY~0pP-a_hqQ_Gd05Y$2MY=sqaQ8u2ZR=}C}z=kgNiSfyo5L}AzTOsLl$^g-*cf-GfcW;4#vKVK{ul|u7eQQJI~hk4_n)Z*C}vcSh=yF64 zx*XAsE=M$?%aN9MIihP_j_5&`BO2S~h@LVc9qMvKo4Op)*e*x3iDOB_x*XA=F6V8} zo_0B6W4jz0AJj*TXhboh5ygn5D=*LtWdrS%2n`PqNV#jPvk&GG+;wHh`f)QCRi@3<=r#3hFf z?KR{jdoZHsUd*vUw*@wbXhBzK!x8Z^%2K}BPpO@dx5;|aE&9wFW!CJ&dhUeTJ+2K4IgV z>=QNwAI5zCFk&n8m7d2l+r6e1r$eCSm|cTDpkPMVd*~U1-dl~89MEic3DQw}gBi~~ zg*6>eZ~B^I*ejrh;76Y4TVr=7f=*LA)HMWNG7cR;`GlM&u+k*2w9cg42(+Axmoc+X z0;+YzL#}lnI}B&mNLOoGNvK(8{uApPQ_5o0OY0u?v-be4LW>WVo3X{Y@M}ScLp0(z>x((|Ky0iKSm!WOTHLqR#0kkLqoA zzuQ);zad>g#&Os=ZU*XfzkdS#2-KV25B(#(YBsIB&(KI#oj?u2%P!)P-06m%gvSk9 zv%4AUpd8Wkk*VyPHM;ueT3M; zj0>=>GXzwUvEN^mp_OIG7_7*cd8sn1onH6rhuACabvrS;nAzEIzZ!Xa{P)58H{OUl za;j3_8QONxNpuWi@BEl!d;E9p!u~VLLv2nP#kONy27!9rcReiyRje(locc3rE>bd8`s*r@b+|z-`XXx=CvzR^Znv4oh?|aif_GI6i zzCZMjJc^nKt+vVE<&`1zbdMXu+Med$E_Z1W&gD$Kv@ftTP?x(GR-}6vL|pA>QJFz6 z->=kRKv8GMRjd&edK~NvwWG?^b}?eLZ!zq_Wd@zliyaoAT;J&>_|;dS93RQqjJ!xi zwo*5O7WHj|l`CnT_T7xUEhfit@M$`LR%qhyVT+zLv1cK68Bo1TR*(9v-lbifk3cK* zU2qB8x@Kcl$QQ_o%Tjh-UkQ=cd`-Q=KohGGkRVzUc; zpKQwdSKvElJ3%q8-a=!gXg9RpXy-8~C7v;e5k=N9C$ixXI0voS_|#+*TU|O!A(^(i zuVAb)qVq^bbTYz-+DrB?Co;y95G)+@`F51on|>T_z}#gJjpX}**ot-nH3YxeQmZZ# zo96XGg+A(F9u*D2nbXiS(Aap!2iOH$iFEOdS3I6;eDBR?E$*=EfDXH^=&Lh3*oqG2>I@xW}M9kb~+)EOK-hv~x8) zBZG>)9No63yKPT*+n!!wW~P0{>k%pc!>PGJq3flGt6Y|Sgg*W_k2K=T7)j_&D5+Tb) zsLFbC!HmPvt7DL^HDmcxSV01@r?9C(ufvLN38XW&goLI56=dYz3wc8Sq8VB6v#Gpj z#)3_7)`8ge4Dw&d>P0g;-vj3+-M6rHq^Iq6u5EUykEpzy$T#ouNG|f-3f(vnv}IPq znq8S8cwTKpY_m&q=uJRT=X#7wvYjE#|nbGzjJSEVYef1NuhYZx}Bm43fL+hBJ)#ZjpmS(Y`Ek?Q<42`T5rEB$(m10Cz ziV<1R4gWQ{doTpbBRZJb=_JLS!BB;vZUB>)EB#r^pZC@uhrMC+$GD{1{3)gWjua#5`)`Mn0fT-I zw9KLvKsvHRkK`>V67)L{ooqR4=a_NRlIZ!Xd0{Bf951 zM)6G2&SBJ6katQ7x|}UDfC7Ot&eI_ z&W5ES`E}|~kAueunU^@w+IZNFe(jD|wyv1wD z$+oBS?Ky0#UW64Id0;gut2#K{uzDU|F0DRmQvUfmW`D8_DfeRqbOh2>q`b47dpcJ; zmvOqrlnwS||F2%tT@B7#?v+=QvMKg+&N6kp15Kp1Rixa5dFx8hiZaiS;up_N?2j+P z9srf49ErZX*Px})YzPfKeK}hG8fbZX7pz!T0kx)n_KH$p0tNM<$gx2Ty_J&Q%Uai( zI_WONLeo5V(#8*47KCx?YSMTY8rZB z3TRcC58Q!MD4^My)$b~G08mZl1MobKAY}YWvOcq%)4peKq$YC=dX-`aQ^>x6Jynr* z(kWV18`?&&FQ)*NxF>irC~?oM!PUn3s|Ck73)dMUHAmPIRhLuHT+} zzr@{f4*RDg`l=50;H#axci_GMnw0U_DrxU&0z}EX6K{?PLqmM%7SfDchrqJC-ftmw!tDnw83;cre^*=GrX?;|$AK6i> zZltT%?|QT%e~x!XTIBx%d-`<3TWIsv>vP6)4jp-UF>}yl_e*r-MQAX!Emt488Fr3g zN&6!`=<^DodaVz{9sp2T%E~7p32@Mxz6|#2EYNz>eUK1Yq~Y|(()e7m#{VeBIgN_W z%#Ui7x{1=6`v+}6t$Gv8oTT?7=_4Cy^(<)h{zs6G)(~BKU+C4xpjAa8=>5-uy7WcU zCHAb-Ikqm6cdt@wOzivjb8NNIapJEllTP9`+5j!k{jd=vwFZAK)~lq64Sw-P;_il! z_%=va6Y?NNSEVJhjga^#ogD=#rQxk%y-DMETvet z0iFVn_`VZZRypnnEHKd)*fHIkN#}3ZAV-P27sftY>Jx8P>Uz+k?$S@NF9ozBGX*<_ zZ9x5*H&0XQexQX8Y3!2*U5y-MpIi06!1Hp@hJ6oUhJ6F5$X)so+maFA%{5BB1KJ`- z&bEhrU?m#QgcxXpV6N|wdrw< z?1$+nofuyRnvPDvc*C$%z4jJOFiJD$wTSKYKd?Vm;6SbJT@Ujrrq_Q9Xt#qFjqbPx zUav_fC#{`&hp&}-6||ga5$wyG1}V=DO?(Hm+$fy~d;rw%|L9%ir5i-OpPC%U zwnGzvR`_LSqTj#sUvLk=(CXj;I2%I3&P!-7$)Lq~q7?cAT1m8VU!Ji`qQ9Tw`99IJ zExH-rI_Yjn^xzeOw)9FViQe%CF0Ulox(DlcN%T)1YH{R7REr~WE{WcQ+UN#ENwf@g zFuKB`4%9}{Er}k5+8FKT^-)RmAE=G|;*#i7sDoqYdZ^8|tsswF!H3v?d9rF53ocCKJ2iwu0Wq%yhk> zHSEW-3a0*O)5Sa)ihXDm)um^!C>0?TMLbLdYP7sQkZ+u`(UbQdoZ;W zoVJ*HgW!}_S;5o>a7yc_VCv(@dxwe50H=&z0H^mF+Bx8qv?-YSxlN}%-3X>G2Y

    935wA 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 Zg%%~7-CNF1 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 z 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

    0C66SW@`~zSPK2{&>y!j`*-ZSm> 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 + + + + + + + + diff --git a/ModSettings.xml b/ModSettings.xml new file mode 100644 index 0000000..f2d0585 --- /dev/null +++ b/ModSettings.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..7900a46 --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("CommonUtilityLib")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CommonUtilityLib")] +[assembly: AssemblyCopyright("Copyright © 2022")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("1a3e0def-d290-4d3e-bc2d-1b66ab174f47")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/README.md b/README.md new file mode 100644 index 0000000..bb9ccf3 --- /dev/null +++ b/README.md @@ -0,0 +1,144 @@ +# Killing Floor 2 Utility Library +This mod adds ItemActions, MinEventActions, Requirements and MonoScripts that provide utilities inspired by Killing Floor 2. It's mainly a common lib for my future killing floor 2 style mods, but might also be useful for other modders. + +This Readme will summarize the usage of these utilitties. + +## ItemActions +There are 3 new actions available currently. +#### 🔴ItemActionHoldOpen +This action adds an **empty** state to the weapon, to easily enable guns to go into a hold open state when magazine is depleted. The state is synced on all clients, and retained on switching equipment. + +To use this action on your weapon, replace +```xml + + +``` +with +```xml + + +``` +, then add an **empty** Bool parameter to your animator. + +Note this only works for Ranged weapons, not Launcher weapons. + +#### 🔴ItemActionAltMode +This action derives from ItemActionHoldOpen, allows you to manage weapon mode with cvar easily. It adds following xml properties: + +- `Cvar_State_Switch`: The cvar that controls the mode. When the value is 0, original properties are used; when the value is greater than 0, the alt properties with that value as index is used instead. +- `Alt_Sound_Start`: The start sounds of each mode, separated by comma(,). Replaces `Sound_start` when in alt mode. +- `Alt_Sound_Empty`: The empty sounds of each mode, separated by comma(,). Replaces `Sound_empty` when in alt mode. +- `Alt_Sound_Loop`: The loop sounds of each mode, separated by comma(,). Replaces `Sound_loop` when in alt mode. +- `Alt_Sound_End`: The end sounds of each mode, separated by comma(,). Replaces `Sound_end` when in alt mode. +- `Alt_InfiniteAmmo`: Whether each alt mode is infinite ammo, separated by comma(,). Valid values are **true** and **false**. + +Sound properties should also work on item modifiers. + +It also adds Bool parameters to the animator, with the name of `"altMode" + Cvar_State_Switch value`, in which the value starts from 1 instead of 0. So for example you have 2 alt modes, then the parameters should be "altMode1" and "altMode2". + +To use this action on your weapon, in addition to ItemActionHoldOpen, replace the class name with **AltMode,KFCommonUtilityLib**, and add your properties accordingly. + +Note that not all properties are required, the missing sounds are defaulted to no sound and infinite ammo is defaulted to false. + +#### 🔴ItemActionRechargeable +This action derives from ItemActionAltMode, allows you to consume different cvars according to weapon mode on bursting shots easily. It adds following xml properties: + +- `Cvar_To_Consume`: The cvar "stock" to consume on fire shots, separated by comma(,). +- `Cvar_Consumption`: The cvar "consumption" on each shot, separated by comma(,). When the stock value is less than consumption value, the corresponding empty sound of current mode is played. +- `Cvar_No_Consumption_Burst_Count`: The shot count that does not consume the stock, separated by comma(,). This is decreased by 1 on each shot. Only in effect when greater than 0. + +These properties only work when in alt modes. + +To use this action on your weapon, in addition to ItemActionAltMode, replace the class name with **Rechargeable,KFCommonUtilityLib**, and add your properties accordingly. + +Note that while `Cvar_No_Consumption_Burst_Count` is not required, the other 2 are a must. + +## MinEventActions +There are currently 6 trigger actions avaliable . + +#### 🔴MinEventActionAddBuffToTargetAndSelf +A simple addon to AddBuff that adds the same buff to the initiator as the targets. + +Syntax is the same as AddBuff, replace `action` value with **AddBuffToTargetAndSelf,KFCommonUtilityLib**. + +#### 🔴MinEventActionBroadcastPlaySoundLocal +A simple addon to PlaySound that ensures broadcast sounds only start broadcasting on the local client. + +Does an additional isRemote check on the entity, so that redundant triggers on other clients won't play the sound. + +Syntax is the same as PlaySound, replace `action` value with **BroadcastPlaySoundLocal,KFCommonUtilityLib**. + +#### 🔴MinEventActionDecreaseProgressionLevelAndRefundSP +A simple addon to SetProgressionLevel that refunds all skill points spent on those decreased levels. + +Syntax is the same as SetProgressionLevel, replace `action` value with **DecreaseProgressionLevelAndRefundSP,KFCommonUtilityLib**. `level` must be less than current progression level. + +#### 🔴MinEventActionModifyCVarWithSelfRef +A simple addon to ModifyCVar that takes "@cvar" reference from the initiator instead of each target. + +When using ModifyCVar with "@cvar", the actuall value is taken from each target. this action changes the behaviour to take the value from the initiator only. + +Syntax is the same as ModifyCVar, replace `action` value with **ModifyCVarWithSelfRef,KFCommonUtilityLib**. + +------------ + + +### WeaponLabels +The following 3 actions controls the 3D Text gameobjects on your weapon, setting their text by string, cvar value or rounds in magazine. Moreover, they can change the color of certain materials. + +Drag **KFUtilAttached** folder into your unity project and attach the script inside to the root transform of your weapon. Then create 3D Text objects and drag them onto the script. You can also drag mesh renderers onto the script to change its color on certain shader properties in xml. + +By "slot", the attribute refers to the index of the objects you dragged onto the script. + +**Text and colors are synced on all clients through NetPackages, thus you should avoid setting them frequently.** +#### 🔴MinEventActionSetStringOnWeaponLabel +This action changes the text of specified 3D Text object. The syntax is as follows: + +```xml + +``` + +When `cvar` is presented, the text will be the cvar value; when `text` is presented, the text will be the string you put on it. + +`slot` is defaulted to 0. + +#### 🔴MinEventActionSetAmmoOnWeaponLabel +This action changed the text of specified 3D Text object to the round count in your magazine. The syntax is as follows: + +```xml + +``` +`slot` is defaulted to 0. + +#### 🔴MinEventActionSetWeaponLabelColor +This action changes the color of specified 3D Text object or the material of specified mesh renderer. The syntax is as follows: + +```xml + + +``` + +When `is_text` is set to true, only `slot0` is parsed, which represents the index of 3D Text object; when `is_text` is set to false, `slot0` represents the index of mesh renderers you dragged onto the script, and `slot1` represents the index of materials on that renderer, while `name` stands for the color property name of the shader. + +`is_text` is defaulted to true, `slot0` and `slot1` are both defaulted to 0. + +For more information about property name and color format, refer to [Unity Doc](https://docs.unity3d.com/ScriptReference/Material.SetColor.html). + +------------ + +## Requirements +There is currently only 1 requriement avaliable. +#### 🔴RoundsInHoldingItem +This requirement can be used to check rounds in magazine on `onSelfEquipStart`. I add this because vanilla `RoundsInMagazine` does not work properly when you start equipping a gun. + +Syntax is the same as `RoundsInMagazine`, replace `name` value with **RoundsInHoldingItem,KFCommonUtilityLib**. + +## Explosion Scripts +There is currently only 1 explosion script avaliable. + +If you have no idea what this does, please refer to my custom explosion particle tutorial. +#### 🔴ExplosionAreaBuffTick +This script requires a trigger collider on the root transform, and add buffs specified in `Explosion.Buff` to all entities inside the collider every `Explosion.TickInterval` seconds. Moreover, it fires `onSelfAttackedOther` event from the item and initiator every tick. + +This script takes following custom property: +- `Explosion.TickInterval`: interval between each tick. Default value is 0.5. diff --git a/Resources/PIPScope.unity3d b/Resources/PIPScope.unity3d new file mode 100644 index 0000000000000000000000000000000000000000..0972abddd1a286cb91985dc852cb3253f04795dd GIT binary patch literal 23215 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 ZB@DyI)Yy)c9vrK#X0ckyf>$B{{4eQ-k_`X= literal 0 HcmV?d00001 diff --git a/Scripts/Attributes/ActionDataTargetAttribute.cs b/Scripts/Attributes/ActionDataTargetAttribute.cs new file mode 100644 index 0000000..a19cafd --- /dev/null +++ b/Scripts/Attributes/ActionDataTargetAttribute.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KFCommonUtilityLib.Scripts.Attributes +{ + [System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + public class ActionDataTargetAttribute : Attribute + { + public ActionDataTargetAttribute(Type DataType) + { + this.DataType = DataType; + } + public Type DataType { get; } + } +} diff --git a/Scripts/Attributes/MethodTargetAttribute.cs b/Scripts/Attributes/MethodTargetAttribute.cs new file mode 100644 index 0000000..24bc271 --- /dev/null +++ b/Scripts/Attributes/MethodTargetAttribute.cs @@ -0,0 +1,45 @@ +using System; +using HarmonyLib; + +namespace KFCommonUtilityLib.Scripts.Attributes +{ + public interface IMethodTarget + { + + } + + [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] + public sealed class MethodTargetPrefixAttribute : Attribute, IMethodTarget + { + public MethodTargetPrefixAttribute() + { + + } + } + + [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] + public sealed class MethodTargetPostfixAttribute : Attribute, IMethodTarget + { + public MethodTargetPostfixAttribute() + { + + } + } + + [AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)] + public sealed class MethodTargetTranspilerAttribute : Attribute, IMethodTarget + { + public MethodTargetTranspilerAttribute() + { + + } + } + + public static class IMethodTargetExtension + { + public static string GetTargetMethodIdentifier(this HarmonyMethod self) + { + return (self.methodName ?? "this[]") + (self.argumentTypes == null ? string.Empty : string.Join(",", Array.ConvertAll(self.argumentTypes, type => type.FullDescription()))); + } + } +} diff --git a/Scripts/Attributes/PatchTargetAttribute.cs b/Scripts/Attributes/PatchTargetAttribute.cs new file mode 100644 index 0000000..54f5903 --- /dev/null +++ b/Scripts/Attributes/PatchTargetAttribute.cs @@ -0,0 +1,16 @@ +using System; + +namespace KFCommonUtilityLib.Scripts.Attributes +{ + [System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + public sealed class TypeTargetAttribute : Attribute + { + // This is a positional argument + public TypeTargetAttribute(Type baseType) + { + BaseType = baseType; + } + + public Type BaseType { get; } + } +} diff --git a/Scripts/Attributes/TypeTargetExtensionAttribute.cs b/Scripts/Attributes/TypeTargetExtensionAttribute.cs new file mode 100644 index 0000000..ddd60d1 --- /dev/null +++ b/Scripts/Attributes/TypeTargetExtensionAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace KFCommonUtilityLib.Scripts.Attributes +{ + [AttributeUsage(System.AttributeTargets.Class, Inherited = false, AllowMultiple = false)] + public class TypeTargetExtensionAttribute : Attribute + { + public Type ModuleType { get; } + public TypeTargetExtensionAttribute(Type moduleType) + { + ModuleType = moduleType; + } + } +} diff --git a/Scripts/ConsoleCmd/ConsoleCmdCalibrateWeapon.cs b/Scripts/ConsoleCmd/ConsoleCmdCalibrateWeapon.cs new file mode 100644 index 0000000..157d2d0 --- /dev/null +++ b/Scripts/ConsoleCmd/ConsoleCmdCalibrateWeapon.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +public class ConsoleCmdCalibrateWeapon : ConsoleCmdAbstract +{ + public override void Execute(List _params, CommandSenderInfo _senderInfo) + { + if (!_senderInfo.IsLocalGame || _params.Count < 2) + { + Log.Error("too few params: expecting 2 at least"); + return; + } + + bool flag = Enum.TryParse(_params[0], out var calType); + if (!flag) + { + Log.Error("Only following commands are valid: " + string.Join(",", Enum.GetNames(typeof(CalibrateType)))); + return; + } + + flag = Enum.TryParse(_params[1], out var tweakType); + if (!flag) + { + Log.Error("Only following tweak type are valid: " + String.Join(",", Enum.GetNames(typeof(TweakType)))); + return; + } + + Transform targetTrans = null; + var inv = GameManager.Instance.World.GetPrimaryPlayer().inventory; + if (calType != CalibrateType.offset) + { + var weaponTrans = inv.GetHoldingItemTransform(); + if (weaponTrans == null) + { + Log.Error("player is not holding anything!"); + return; + } + + targetTrans = weaponTrans.Find(_params[2]); + if (targetTrans == null) + { + Log.Error("transform not found on weapon!"); + return; + } + } + + Vector3 param = Vector3.zero; + if (tweakType != TweakType.log) + { + int parseIndex; + if (calType != CalibrateType.offset) + { + parseIndex = 3; + if (_params.Count < 4) + { + Log.Error("relative or absolute value is required to calibrate!"); + return; + } + } + else + { + parseIndex = 2; + if (_params.Count < 3) + { + Log.Error("offset value is required to calibrate!"); + return; + } + } + + if (_params.Count < parseIndex + 2) + param = StringParsers.ParseVector3(_params[parseIndex]); + else if (_params.Count == parseIndex + 2) + { + flag = float.TryParse(_params[parseIndex + 1], out float value); + if (!flag) + { + Log.Error("offset value is NAN!"); + return; + } + + switch (_params[parseIndex]) + { + case "x": + param.x = value; + break; + case "y": + param.y = value; + break; + case "z": + param.z = value; + break; + default: + Log.Error("must specify x/y/z axis!"); + return; + } + } + else + { + Log.Error("too many params!"); + return; + } + } + + switch (calType) + { + case CalibrateType.pos: + targetTrans.localPosition = DoCalibrate(tweakType, targetTrans.localPosition, param); + break; + case CalibrateType.rot: + targetTrans.localEulerAngles = DoCalibrate(tweakType, targetTrans.localEulerAngles, param); + break; + case CalibrateType.scale: + targetTrans.localScale = DoCalibrate(tweakType, targetTrans.localScale, param); + break; + case CalibrateType.offset: + //var zoomAction = Convert.ChangeType(inv.holdingItemData.actionData[1], typeof(ItemActionZoom).GetNestedType("ItemActionDataZoom", System.Reflection.BindingFlags.NonPublic)); + if (!(inv.holdingItemData.actionData[1] is ItemActionZoom.ItemActionDataZoom zoomAction)) + { + Log.Error("holding item can not aim!"); + return; + } + zoomAction.ScopeCameraOffset = DoCalibrate(tweakType, zoomAction.ScopeCameraOffset, param); + break; + } + } + + private Vector3 DoCalibrate(TweakType type, Vector3 origin, Vector3 param) + { + Vector3 res = origin; + switch (type) + { + case TweakType.abs: + res = param; + break; + case TweakType.rel: + res = origin + param; + break; + case TweakType.log: + Log.Out(res.ToString("F6")); + break; + } + return res; + } + + public override string[] getCommands() + { + return new string[] { "calibrate", "calib" }; + } + + public override string getDescription() + { + return "adjust weapon transform rotation, position, scale, scope offset in game and print current value for xml editing purpose."; + } + + public override bool IsExecuteOnClient => true; + + public override int DefaultPermissionLevel => 1000; + + private enum CalibrateType + { + pos, + rot, + scale, + offset + } + + private enum TweakType + { + abs, + rel, + log + } +} + diff --git a/Scripts/ConsoleCmd/ConsoleCmdListParticleScripts.cs b/Scripts/ConsoleCmd/ConsoleCmdListParticleScripts.cs new file mode 100644 index 0000000..f266313 --- /dev/null +++ b/Scripts/ConsoleCmd/ConsoleCmdListParticleScripts.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +public class ConsoleCmdListParticleScripts : ConsoleCmdAbstract +{ + public override bool IsExecuteOnClient => true; + + public override bool AllowedInMainMenu => false; + + public override void Execute(List _params, CommandSenderInfo _senderInfo) + { + if(_params.Count > 1) + { + Log.Error("Invalid param count: expecting 0 or 1!"); + return; + } + + if (_params.Count == 0) + { + HashSet typeNames = new HashSet(); + foreach (var pe in ParticleEffect.loadedTs.Values) + { + foreach (var script in pe.GetComponentsInChildren()) + { + typeNames.Add(script.GetType().AssemblyQualifiedName); + } + } + string print = string.Join("\n", typeNames.ToList().OrderBy(s => s)); + Log.Out($"Listing all scripts...\n{print}\n"); + } + else + { + int id = ParticleEffect.ToId(_params[0]); + var pe = ParticleEffect.GetDynamicTransform(id); + if (pe) + { + string print = ""; + foreach (var script in pe.GetComponentsInChildren()) + { + print += $"{(script.transform.parent != null ? pe.GetChildPath(script.transform) : script.transform.name)} - {script.GetType().AssemblyQualifiedName}\n"; + } + Log.Out($"{_params[0]} has following scripts attached:\n{print}"); + } + } + } + + public override string[] getCommands() + { + return new[] { "listpes" }; + } + + public override string getDescription() + { + return "list monobehaviour on all the particle effects that are currently loaded, or the specified one only."; + } +} \ No newline at end of file diff --git a/Scripts/ConsoleCmd/ConsoleCmdMultiActionItemValueDebug.cs b/Scripts/ConsoleCmd/ConsoleCmdMultiActionItemValueDebug.cs new file mode 100644 index 0000000..6acb6fe --- /dev/null +++ b/Scripts/ConsoleCmd/ConsoleCmdMultiActionItemValueDebug.cs @@ -0,0 +1,59 @@ +using HarmonyLib; +using System.Collections.Generic; +using System.Reflection; + +namespace KFCommonUtilityLib.Scripts.ConsoleCmd +{ + public class ConsoleCmdMultiActionItemValueDebug : ConsoleCmdAbstract + { + public override bool IsExecuteOnClient => true; + + public override int DefaultPermissionLevel => base.DefaultPermissionLevel; + + public override bool AllowedInMainMenu => false; + + public override void Execute(List _params, CommandSenderInfo _senderInfo) + { + EntityPlayerLocal player = GameManager.Instance.World?.GetPrimaryPlayer(); + if (player) + { + ItemValue itemValue = player.inventory.holdingItemItemValue; + LogMeta(itemValue); + } + } + + public static void LogMeta(ItemValue itemValue) + { + if (itemValue != null && itemValue.ItemClass != null) + { + var metadata = itemValue.Metadata; + if (metadata != null) + { + Log.Out("Logging metadata..."); + foreach (var pair in metadata) + { + if (pair.Value != null) + { + Log.Out($"key: {pair.Key}, type: {pair.Value.typeTag.ToString()}, value: {pair.Value.GetValue()}"); + } + } + } + else + { + Log.Out("Metadata is null!"); + } + Log.Out($"meta: {itemValue.Meta}, ammo index: {itemValue.SelectedAmmoTypeIndex}"); + } + } + + public override string[] getCommands() + { + return new string[] { "maivd" }; + } + + public override string getDescription() + { + return "Debug ItemValue metadata and stuff."; + } + } +} diff --git a/Scripts/ConsoleCmd/ConsoleCmdPlayerDebugInfo.cs b/Scripts/ConsoleCmd/ConsoleCmdPlayerDebugInfo.cs new file mode 100644 index 0000000..081a733 --- /dev/null +++ b/Scripts/ConsoleCmd/ConsoleCmdPlayerDebugInfo.cs @@ -0,0 +1,59 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using UnityEngine; + +namespace KFCommonUtilityLib.Scripts.ConsoleCmd +{ + public class ConsoleCmdPlayerDebugInfo : ConsoleCmdAbstract + { + public override bool IsExecuteOnClient => true; + + public override void Execute(List _params, CommandSenderInfo _senderInfo) + { + EntityPlayerLocal player = GameManager.Instance.World.GetPrimaryPlayer(); + RenderTexture playerCamRT = player.playerCamera.targetTexture; + if (playerCamRT != null) + SaveTextureToFileUtility.SaveTextureToFile(playerCamRT, Application.dataPath + playerCamRT.name, playerCamRT.width, playerCamRT.height, SaveTextureToFileUtility.SaveTextureFileFormat.PNG, 95, true, (bool res) => Log.Out(res ? $"player camera rendertexture saved to {Application.dataPath}" : "failed to save player camera render texture!")); + RenderTexture finalCamRT = player.finalCamera.targetTexture; + if (finalCamRT != null) + SaveTextureToFileUtility.SaveTextureToFile(finalCamRT, Application.dataPath + finalCamRT.name, finalCamRT.width, finalCamRT.height, SaveTextureToFileUtility.SaveTextureFileFormat.PNG, 95, true, (bool res) => Log.Out(res ? $"final camera rendertexture saved to {Application.dataPath}" : "failed to save final camera render texture!")); + Renderer[] renderers = player.gameObject.GetComponentsInChildren(); + Log.Out($"renderers layers: \n{string.Join("\n", renderers.Select(r => r.gameObject.name + " layer:" + r.gameObject.layer))})"); + Log.Out($"player transform values: {player.transform.name} {player.transform.position}/{player.transform.eulerAngles}"); + Log.Out($"player camera transform values: {player.playerCamera.transform.parent.name}/{player.playerCamera.gameObject.name} {player.playerCamera.transform.localPosition}/{player.playerCamera.transform.localEulerAngles} viewport {player.playerCamera.rect} render layers {player.playerCamera.cullingMask} fov {player.playerCamera.fieldOfView}"); + Log.Out($"final camera transform values: {player.finalCamera.transform.parent.name}/{player.finalCamera.gameObject.name} {player.finalCamera.transform.localPosition}/{player.finalCamera.transform.localEulerAngles} viewport {player.finalCamera.rect} render layers {player.finalCamera.cullingMask} fov {player.finalCamera.fieldOfView}"); + Log.Out($"vp components list:\n{string.Join("\n", player.RootTransform.GetComponentsInChildren().Select(c => c.GetType().Name + " on " + c.transform.name))}"); + foreach (var animator in player.RootTransform.GetComponentsInChildren()) + { + Log.Out($"animator transform {animator.name} values: {animator.transform.localPosition}/{animator.transform.localEulerAngles}"); + } + Log.Out("PRINTING PLAYER HIERARCHY:"); + Log.Out(PrintTransform(player.RootTransform)); + + Transform fpsArm = ((AvatarLocalPlayerController)player.emodel.avatarController).FPSArms.animator.transform; + Log.Out($"FPS ARM:\nparent {fpsArm.parent.name}\n{PrintTransform(fpsArm)}"); + } + + private static string PrintTransform(Transform parent, string str = "", int indent = 0) + { + str += "".PadLeft(indent * 4) + $"{parent.name}/pos:{parent.transform.localPosition}/rot:{parent.localEulerAngles}" + "\n"; + indent++; + foreach (Transform child in parent) + { + str = PrintTransform(child, str, indent); + } + return str; + } + + public override string[] getCommands() + { + return new string[] { "printpinfo" }; + } + + public override string getDescription() + { + return "print player debug info."; + } + } +} diff --git a/Scripts/ConsoleCmd/ConsoleCmdPrintLocalCache.cs b/Scripts/ConsoleCmd/ConsoleCmdPrintLocalCache.cs new file mode 100644 index 0000000..ca8d927 --- /dev/null +++ b/Scripts/ConsoleCmd/ConsoleCmdPrintLocalCache.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; + +namespace KFCommonUtilityLib.Scripts.ConsoleCmd +{ + public class ConsoleCmdPrintLocalCache : ConsoleCmdAbstract + { + public override bool IsExecuteOnClient => true; + + public override bool AllowedInMainMenu => false; + + public override int DefaultPermissionLevel => 1000; + + public override void Execute(List _params, CommandSenderInfo _senderInfo) + { + if (_params.Count != 1) + return; + int index = int.Parse(_params[0]); + var player = GameManager.Instance.World.GetPrimaryPlayer(); + if (player != null && player.inventory.holdingItemData.actionData[index] is IModuleContainerFor module) + { + ActionModuleLocalPassiveCache.LocalPassiveCacheData instance = module.Instance; + foreach (int hash in instance) + { + Log.Out($"cache {instance.GetCachedName(hash)} value {instance.GetCachedValue(hash)}"); + + } + } + } + + public override string[] getCommands() + { + return new[] { "plc" }; + } + + public override string getDescription() + { + return "Show local cache for current holding item."; + } + } +} diff --git a/Scripts/ConsoleCmd/ConsoleCmdReloadLog.cs b/Scripts/ConsoleCmd/ConsoleCmdReloadLog.cs new file mode 100644 index 0000000..039e860 --- /dev/null +++ b/Scripts/ConsoleCmd/ConsoleCmdReloadLog.cs @@ -0,0 +1,28 @@ +using System.Collections.Generic; + +public class ConsoleCmdReloadLog : ConsoleCmdAbstract +{ + public static bool LogInfo { get; private set; } = false; + + public override bool IsExecuteOnClient => true; + + public override bool AllowedInMainMenu => false; + + public override int DefaultPermissionLevel => 1000; + + public override void Execute(List _params, CommandSenderInfo _senderInfo) + { + LogInfo = !LogInfo; + Log.Out($"Log Reload Info: {LogInfo}"); + } + + public override string[] getCommands() + { + return new string[] { "reloadlog", "rlog" }; + } + + public override string getDescription() + { + return "Print reload animation length and multiplier."; + } +} \ No newline at end of file diff --git a/Scripts/FbxExporter07.cs b/Scripts/FbxExporter07.cs new file mode 100644 index 0000000..c44512f --- /dev/null +++ b/Scripts/FbxExporter07.cs @@ -0,0 +1,753 @@ +// *********************************************************************** +// Copyright (c) 2017 Unity Technologies. All rights reserved. +// +// Licensed under the ##LICENSENAME##. +// See LICENSE.md file in the project root for full license information. +// *********************************************************************** + +using Autodesk.Fbx; +using System.Collections.Generic; +using System.IO; +using UnityEngine; + +public class FbxExporter07 : System.IDisposable +{ + const string Title = + "Example 07: exporting a skinned mesh with bones"; + + const string Subject = + @"Example FbxExporter07 illustrates how to: + 1) create and initialize an exporter + 2) create a scene + 3) create a skeleton + 4) exported mesh + 5) bind mesh to skeleton + 6) create a bind pose + 7) export the skinned mesh to a FBX file (FBX201400 compatible) + "; + + const string Keywords = + "export skeleton mesh skin cluster pose"; + + const string Comments = + ""; + + const string MenuItemName = "File/Export FBX/7. Skinned mesh with bones"; + + const string FileBaseName = "example_skinned_mesh_with_bones"; + + ///

    + /// Create instance of example + /// + public static FbxExporter07 Create() { return new FbxExporter07(); } + + /// + /// Export GameObject's as a skinned mesh with bones + /// + protected void ExportSkinnedMesh(Animator unityAnimator, FbxScene fbxScene, FbxNode fbxParentNode) + { + GameObject unityGo = unityAnimator.gameObject; + + SkinnedMeshRenderer unitySkin = unityGo.GetComponentInChildren(); + + if (unitySkin == null) + { + Log.Error("could not find skinned mesh"); + return; + } + + var meshInfo = GetSkinnedMeshInfo(unitySkin.gameObject); + + if (meshInfo.renderer == null) + { + Log.Error("mesh has no renderer"); + return; + } + + // create an FbxNode and add it as a child of fbxParentNode + FbxNode fbxNode = FbxNode.Create(fbxScene, meshInfo.unityObject.name); + SetNodeMatrix(fbxNode, meshInfo.unityObject.transform); + + + Dictionary boneNodes = new Dictionary(); + + // export skeleton + if (ExportSkeleton(meshInfo, fbxScene, fbxNode, boneNodes, out FbxNode meshNode)) + { + // export skin + FbxNode fbxMeshNode = ExportMesh(meshInfo, fbxScene, fbxNode, meshNode); + + FbxMesh fbxMesh = fbxMeshNode.GetMesh(); + + if (fbxMesh == null) + { + Log.Error("Could not find mesh"); + return; + } + + // bind mesh to skeleton + ExportSkin(meshInfo, fbxScene, fbxMesh, fbxParentNode, boneNodes); + + // add bind pose + ExportBindPose(fbxNode, fbxMeshNode, fbxScene, boneNodes); + + fbxParentNode.AddChild(fbxNode); + NumNodes++; + + if (Verbose) + Log.Out(string.Format("exporting {0} {1}", "Skin", fbxNode.GetName())); + } + else + { + Log.Error("failed to export skeleton"); + } + } + + /// + /// Export bones of skinned mesh + /// + protected bool ExportSkeleton(MeshInfo meshInfo, FbxScene fbxScene, FbxNode fbxParentNode, Dictionary boneNodes, out FbxNode meshNode) + { + SkinnedMeshRenderer unitySkinnedMeshRenderer = meshInfo.renderer as SkinnedMeshRenderer; + meshNode = null; + if (unitySkinnedMeshRenderer.bones.Length <= 0) + { + return false; + } + + Dictionary boneBindPose = new Dictionary(); + + for (int boneIndex = 0; boneIndex < unitySkinnedMeshRenderer.bones.Length; boneIndex++) + { + Transform unityBoneTransform = unitySkinnedMeshRenderer.bones[boneIndex]; + + FbxNode fbxBoneNode = FbxNode.Create(fbxScene, unityBoneTransform.name); + + // Create the node's attributes + FbxSkeleton fbxSkeleton = FbxSkeleton.Create(fbxScene, unityBoneTransform.name + "_Skel"); + + var fbxSkeletonType = FbxSkeleton.EType.eLimbNode; + if (unityBoneTransform == unityBoneTransform.root || fbxParentNode.GetName().Equals(unityBoneTransform.parent.name)) + { + fbxSkeletonType = FbxSkeleton.EType.eRoot; + } + fbxSkeleton.SetSkeletonType(fbxSkeletonType); + fbxSkeleton.Size.Set(1.0f); + + // Set the node's attribute + fbxBoneNode.SetNodeAttribute(fbxSkeleton); + + boneBindPose.Add(unityBoneTransform, meshInfo.BindPoses[boneIndex]); + + // save relatation between unity transform and fbx bone node for skinning + boneNodes[unityBoneTransform] = fbxBoneNode; + } + + Transform root = meshInfo.unityObject.transform; + Dictionary dict_empty_parents = new Dictionary(); + // set the hierarchy for the FbxNodes + foreach (KeyValuePair t in boneNodes) + { + + Matrix4x4 pose; + + // if this is a root node then don't need to do anything + if (t.Key == t.Key.root) + { + fbxParentNode.AddChild(t.Value); + + pose = boneBindPose[t.Key].inverse; // assuming parent is identity matrix + SetBoneMatrix(t.Value, pose); + } + else if (!boneNodes.ContainsKey(t.Key.parent)) + { + Transform parent = t.Key.parent, cur = t.Key; + FbxNode parentNode = null, curNode = t.Value; + //pose = GetLocalMatrix(cur); // localToWorld + while (parent != root) + { + if (!boneNodes.TryGetValue(parent, out parentNode)) + { + if (dict_empty_parents.TryGetValue(parent, out parentNode)) + { + parentNode.AddChild(curNode); + pose = GetLocalMatrix(cur, true); + SetBoneMatrix(curNode, pose); + //if (boneNodes.ContainsKey(cur)) + //{ + // pose = GetLocalMatrix(cur, true); + // SetBoneMatrix(curNode, pose); + //} + //else + //{ + // SetNodeMatrix(curNode, cur); + //} + break; + } + else + { + parentNode = FbxNode.Create(fbxScene, parent.name); + parentNode.AddChild(curNode); + pose = GetLocalMatrix(cur, true); + SetBoneMatrix(curNode, pose); + //if (boneNodes.ContainsKey(cur)) + //{ + // pose = GetLocalMatrix(cur, true); + // SetBoneMatrix(curNode, pose); + //} + //else + //{ + // SetNodeMatrix(curNode, cur); + //} + if (parent.TryGetComponent(out _)) + meshNode = parentNode; + dict_empty_parents.Add(parent, parentNode); + cur = parent; + parent = parent.parent; + curNode = parentNode; + parentNode = null; + } + } + else + { + parentNode.AddChild(curNode); + pose = GetLocalMatrix(cur, true); + SetBoneMatrix(curNode, pose); + //if (boneNodes.ContainsKey(cur)) + //{ + // pose = GetLocalMatrix(cur, true); + // SetBoneMatrix(curNode, pose); + //} + //else + //{ + // SetNodeMatrix(curNode, cur); + //} + break; + } + } + if (parent == root) + { + if (parent.TryGetComponent(out _)) + meshNode = fbxParentNode; + fbxParentNode.AddChild(curNode); + if (boneNodes.ContainsKey(cur)) + { + pose = boneBindPose[cur].inverse; + //pose = boneBindPose[parent] * boneBindPose[cur].inverse; + SetBoneMatrix(curNode, pose); + } + else + { + SetNodeMatrix(curNode, cur); + } + } + } + else + { + boneNodes[t.Key.parent].AddChild(t.Value); + + // inverse of my bind pose times parent bind pose + pose = boneBindPose[t.Key.parent] * boneBindPose[t.Key].inverse; + SetBoneMatrix(t.Value, pose); + } + + } + + return true; + } + + private Matrix4x4 GetLocalMatrix(Transform t, bool inverse) + { + //var matrix = Matrix4x4.TRS(t.localPosition, t.localRotation, t.localScale); + var matrix = t.worldToLocalMatrix * t.parent.localToWorldMatrix; + return inverse ? matrix.inverse : matrix; + } + + private void SetBoneMatrix(FbxNode node, Matrix4x4 pose) + { + // use FbxMatrix to get translation and rotation relative to parent + FbxMatrix matrix = new FbxMatrix(); + matrix.SetColumn(0, new FbxVector4(pose.GetRow(0).x, pose.GetRow(0).y, pose.GetRow(0).z, pose.GetRow(0).w)); + matrix.SetColumn(1, new FbxVector4(pose.GetRow(1).x, pose.GetRow(1).y, pose.GetRow(1).z, pose.GetRow(1).w)); + matrix.SetColumn(2, new FbxVector4(pose.GetRow(2).x, pose.GetRow(2).y, pose.GetRow(2).z, pose.GetRow(2).w)); + matrix.SetColumn(3, new FbxVector4(pose.GetRow(3).x, pose.GetRow(3).y, pose.GetRow(3).z, pose.GetRow(3).w)); + + FbxVector4 translation, rotation, shear, scale; + double sign; + matrix.GetElements(out translation, out rotation, out shear, out scale, out sign); + + // Negating the x value of the translation, and the y and z values of the prerotation + // to convert from Unity to Maya coordinates (left to righthanded) + node.LclTranslation.Set(new FbxDouble3(-translation.X, translation.Y, translation.Z)); + node.LclRotation.Set(new FbxDouble3(0, 0, 0)); + node.LclScaling.Set(new FbxDouble3(scale.X, scale.Y, scale.Z)); + + node.SetRotationActive(true); + node.SetPivotState(FbxNode.EPivotSet.eSourcePivot, FbxNode.EPivotState.ePivotReference); + node.SetPreRotation(FbxNode.EPivotSet.eSourcePivot, new FbxVector4(rotation.X, -rotation.Y, -rotation.Z)); + } + + private void SetNodeMatrix(FbxNode node, Transform unityTransform) + { + // get local position of fbxNode (from Unity) + UnityEngine.Vector3 unityTranslate = unityTransform.localPosition; + UnityEngine.Vector3 unityRotate = unityTransform.localRotation.eulerAngles; + UnityEngine.Vector3 unityScale = unityTransform.localScale; + + // transfer transform data from Unity to Fbx + // Negating the x value of the translation, and the y and z values of the rotation + // to convert from Unity to Maya coordinates (left to righthanded) + var fbxTranslate = new FbxDouble3(-unityTranslate.x, unityTranslate.y, unityTranslate.z); + var fbxRotate = new FbxDouble3(unityRotate.x, -unityRotate.y, -unityRotate.z); + var fbxScale = new FbxDouble3(unityScale.x, unityScale.y, unityScale.z); + + // set the local position of fbxNode + node.LclTranslation.Set(fbxTranslate); + node.LclRotation.Set(fbxRotate); + node.LclScaling.Set(fbxScale); + } + + /// + /// Export binding of mesh to skeleton + /// + protected void ExportSkin(MeshInfo meshInfo, FbxScene fbxScene, FbxMesh fbxMesh, FbxNode fbxRootNode, Dictionary boneNodes) + { + SkinnedMeshRenderer unitySkinnedMeshRenderer + = meshInfo.renderer as SkinnedMeshRenderer; + + FbxSkin fbxSkin = FbxSkin.Create(fbxScene, (meshInfo.unityObject.name + "_Skin")); + + FbxAMatrix fbxMeshMatrix = fbxRootNode.EvaluateGlobalTransform(); + + // keep track of the bone index -> fbx cluster mapping, so that we can add the bone weights afterwards + Dictionary boneCluster = new Dictionary(); + + for (int i = 0; i < unitySkinnedMeshRenderer.bones.Length; i++) + { + FbxNode fbxBoneNode = boneNodes[unitySkinnedMeshRenderer.bones[i]]; + + // Create the deforming cluster + FbxCluster fbxCluster = FbxCluster.Create(fbxScene, "BoneWeightCluster"); + + fbxCluster.SetLink(fbxBoneNode); + fbxCluster.SetLinkMode(FbxCluster.ELinkMode.eTotalOne); + + boneCluster.Add(i, fbxCluster); + + // set the Transform and TransformLink matrix + fbxCluster.SetTransformMatrix(fbxMeshMatrix); + + FbxAMatrix fbxLinkMatrix = fbxBoneNode.EvaluateGlobalTransform(); + fbxCluster.SetTransformLinkMatrix(fbxLinkMatrix); + + // add the cluster to the skin + fbxSkin.AddCluster(fbxCluster); + } + + // set the vertex weights for each bone + SetVertexWeights(meshInfo, boneCluster); + + // Add the skin to the mesh after the clusters have been added + fbxMesh.AddDeformer(fbxSkin); + } + + /// + /// set weight vertices to cluster + /// + protected void SetVertexWeights(MeshInfo meshInfo, Dictionary boneCluster) + { + // set the vertex weights for each bone + for (int i = 0; i < meshInfo.BoneWeights.Length; i++) + { + var boneWeights = meshInfo.BoneWeights; + int[] indices = { + boneWeights [i].boneIndex0, + boneWeights [i].boneIndex1, + boneWeights [i].boneIndex2, + boneWeights [i].boneIndex3 + }; + float[] weights = { + boneWeights [i].weight0, + boneWeights [i].weight1, + boneWeights [i].weight2, + boneWeights [i].weight3 + }; + + for (int j = 0; j < indices.Length; j++) + { + if (weights[j] <= 0) + { + continue; + } + if (!boneCluster.ContainsKey(indices[j])) + { + continue; + } + boneCluster[indices[j]].AddControlPointIndex(i, weights[j]); + } + } + } + + /// + /// Export bind pose of mesh to skeleton + /// + protected void ExportBindPose(FbxNode fbxRootNode, FbxNode meshNode, FbxScene fbxScene, Dictionary boneNodes) + { + FbxPose fbxPose = FbxPose.Create(fbxScene, fbxRootNode.GetName()); + + // set as bind pose + fbxPose.SetIsBindPose(true); + + // assume each bone node has one weighted vertex cluster + foreach (FbxNode fbxNode in boneNodes.Values) + { + // EvaluateGlobalTransform returns an FbxAMatrix (affine matrix) + // which has to be converted to an FbxMatrix so that it can be passed to fbxPose.Add(). + // The hierarchy for FbxMatrix and FbxAMatrix is as follows: + // + // FbxDouble4x4 + // / \ + // FbxMatrix FbxAMatrix + // + // Therefore we can't convert directly from FbxAMatrix to FbxMatrix, + // however FbxMatrix has a constructor that takes an FbxAMatrix. + FbxMatrix fbxBindMatrix = new FbxMatrix(fbxNode.EvaluateGlobalTransform()); + + fbxPose.Add(fbxNode, fbxBindMatrix); + } + + FbxMatrix bindMatrix = new FbxMatrix(meshNode.EvaluateGlobalTransform()); + + fbxPose.Add(meshNode, bindMatrix); + + // add the pose to the scene + fbxScene.AddPose(fbxPose); + } + + /// + /// Unconditionally export this mesh object to the file. + /// We have decided; this mesh is definitely getting exported. + /// + public FbxNode ExportMesh(MeshInfo meshInfo, FbxScene fbxScene, FbxNode fbxNode, FbxNode meshNode) + { + if (!meshInfo.IsValid) + { + Log.Error("Invalid mesh info"); + return null; + } + + // create a node for the mesh + if (meshNode == null) + { + meshNode = FbxNode.Create(fbxScene, "geo"); + fbxNode.AddChild(meshNode); + } + + // create the mesh structure. + FbxMesh fbxMesh = FbxMesh.Create(fbxScene, "Mesh"); + + // Create control points. + int NumControlPoints = meshInfo.VertexCount; + fbxMesh.InitControlPoints(NumControlPoints); + + // copy control point data from Unity to FBX + for (int v = 0; v < NumControlPoints; v++) + { + // convert from left to right-handed by negating x (Unity negates x again on import) + fbxMesh.SetControlPointAt(new FbxVector4(-meshInfo.Vertices[v].x, meshInfo.Vertices[v].y, meshInfo.Vertices[v].z), v); + } + + /* + * Create polygons + * Triangles have to be added in reverse order, + * or else they will be inverted on import + * (due to the conversion from left to right handed coords) + */ + for (int f = 0; f < meshInfo.Triangles.Length / 3; f++) + { + fbxMesh.BeginPolygon(); + fbxMesh.AddPolygon(meshInfo.Triangles[3 * f + 2]); + fbxMesh.AddPolygon(meshInfo.Triangles[3 * f + 1]); + fbxMesh.AddPolygon(meshInfo.Triangles[3 * f]); + fbxMesh.EndPolygon(); + } + + // set the fbxNode containing the mesh + meshNode.SetNodeAttribute(fbxMesh); + meshNode.SetShadingMode(FbxNode.EShadingMode.eWireFrame); + + return meshNode; + } + + protected void ExportComponents(GameObject unityGo, FbxScene fbxScene, FbxNode fbxParentNode) + { + Animator unityAnimator = unityGo.GetComponent(); + Log.Out($"Exporting Components: {unityGo.name}, animator: {(unityAnimator == null ? null : unityAnimator.ToString())}"); + if (unityAnimator == null) + return; + + ExportSkinnedMesh(unityAnimator, fbxScene, fbxParentNode); + + return; + } + + /// + /// Export all the objects in the set. + /// Return the number of objects in the set that we exported. + /// + public int ExportAll(IEnumerable unityExportSet) + { + // Create the FBX manager + using (var fbxManager = FbxManager.Create()) + { + // Configure IO settings. + fbxManager.SetIOSettings(FbxIOSettings.Create(fbxManager, Globals.IOSROOT)); + + // Create the exporter + var fbxExporter = FbxExporter.Create(fbxManager, "Exporter"); + + // Initialize the exporter. + int fileFormat = -1; + fileFormat = fbxManager.GetIOPluginRegistry().FindWriterIDByDescription("FBX ascii (*.fbx)"); + bool status = fbxExporter.Initialize(LastFilePath, fileFormat, fbxManager.GetIOSettings()); + + // Check that initialization of the fbxExporter was successful + if (!status) + { + Log.Error("failed to initialize exporter"); + return 0; + } + + // By default, FBX exports in its most recent version. You might want to specify + // an older version for compatibility with other applications. + fbxExporter.SetFileExportVersion("FBX201400"); + + // Create a scene + var fbxScene = FbxScene.Create(fbxManager, "Scene"); + + // create scene info + FbxDocumentInfo fbxSceneInfo = FbxDocumentInfo.Create(fbxManager, "SceneInfo"); + + // set some scene info values + fbxSceneInfo.mTitle = Title; + fbxSceneInfo.mSubject = Subject; + fbxSceneInfo.mAuthor = "Unity Technologies"; + fbxSceneInfo.mRevision = "1.0"; + fbxSceneInfo.mKeywords = Keywords; + fbxSceneInfo.mComment = Comments; + + fbxScene.SetSceneInfo(fbxSceneInfo); + + var fbxSettings = fbxScene.GetGlobalSettings(); + fbxSettings.SetSystemUnit(FbxSystemUnit.m); // Unity unit is meters + + // The Unity axis system has Y up, Z forward, X to the right (left handed system with odd parity). + // The Maya axis system has Y up, Z forward, X to the left (right handed system with odd parity). + // We need to export right-handed for Maya because ConvertScene can't switch handedness: + // https://forums.autodesk.com/t5/fbx-forum/get-confused-with-fbxaxissystem-convertscene/td-p/4265472 + fbxSettings.SetAxisSystem(FbxAxisSystem.MayaYUp); + + FbxNode fbxRootNode = fbxScene.GetRootNode(); + + // export set of objects + foreach (var obj in unityExportSet) + { + var unityGo = GetGameObject(obj); + + if (unityGo) + { + this.ExportComponents(unityGo, fbxScene, fbxRootNode); + } + } + + // Export the scene to the file. + status = fbxExporter.Export(fbxScene); + + // cleanup + fbxScene.Destroy(); + fbxExporter.Destroy(); + + return status == true ? NumNodes : 0; + } + } + + /// + /// Number of nodes exported including siblings and decendents + /// + public int NumNodes { private set; get; } + + /// + /// Clean up this class on garbage collection + /// + public void Dispose() { } + + static bool Verbose { get { return true; } } + const string NamePrefix = ""; + + /// + /// manage the selection of a filename + /// + static string LastFilePath { get; set; } + const string Extension = "fbx"; + + /// + ///Information about the mesh that is important for exporting. + /// + public struct MeshInfo + { + /// + /// The transform of the mesh. + /// + public Matrix4x4 xform; + public Mesh mesh; + public Renderer renderer; + + /// + /// The gameobject in the scene to which this mesh is attached. + /// This can be null: don't rely on it existing! + /// + public GameObject unityObject; + + /// + /// Return true if there's a valid mesh information + /// + /// The vertex count. + public bool IsValid { get { return mesh != null; } } + + /// + /// Gets the vertex count. + /// + /// The vertex count. + public int VertexCount { get { return mesh.vertexCount; } } + + /// + /// Gets the triangles. Each triangle is represented as 3 indices from the vertices array. + /// Ex: if triangles = [3,4,2], then we have one triangle with vertices vertices[3], vertices[4], and vertices[2] + /// + /// The triangles. + public int[] Triangles { get { return mesh.triangles; } } + + /// + /// Gets the vertices, represented in local coordinates. + /// + /// The vertices. + public Vector3[] Vertices { get { return mesh.vertices; } } + + /// + /// Gets the normals for the vertices. + /// + /// The normals. + public Vector3[] Normals { get { return mesh.normals; } } + + /// + /// Gets the uvs. + /// + /// The uv. + public Vector2[] UV { get { return mesh.uv; } } + + public BoneWeight[] BoneWeights { get { return mesh.boneWeights; } } + + public Matrix4x4[] BindPoses { get { return mesh.bindposes; } } + + /// + /// Initializes a new instance of the struct. + /// + /// The GameObject the mesh is attached to. + /// A mesh we want to export + public MeshInfo(GameObject gameObject, Mesh mesh, Renderer renderer) + { + this.renderer = renderer; + this.mesh = mesh; + this.xform = gameObject.transform.localToWorldMatrix; + this.unityObject = gameObject; + } + } + + /// + /// Get a mesh renderer's mesh. + /// + private MeshInfo GetSkinnedMeshInfo(GameObject gameObject) + { + // Verify that we are rendering. Otherwise, don't export. + var renderer = gameObject.GetComponentInChildren(); + if (!renderer) + { + Log.Error("could not find renderer"); + return new MeshInfo(); + } + + var mesh = renderer.sharedMesh; + if (!mesh) + { + Log.Error("Could not find mesh"); + return new MeshInfo(); + } + + return new MeshInfo(gameObject, mesh, renderer); + } + + /// + /// Get the GameObject + /// + private static GameObject GetGameObject(Object obj) + { + if (obj is UnityEngine.Transform) + { + var xform = obj as UnityEngine.Transform; + return xform.gameObject; + } + else if (obj is UnityEngine.GameObject) + { + return obj as UnityEngine.GameObject; + } + else if (obj is Component) + { + var mono = obj as Component; + return mono.gameObject; + } + + return null; + } + + private static string MakeFileName(string basename = "test", string extension = "fbx") + { + return basename + "." + extension; + } + + // use the SaveFile panel to allow user to enter a file name + public static void OnExport(IEnumerable objects, string filePath = null) + { + if (!File.Exists(filePath)) + filePath = Path.Combine(Application.dataPath, MakeFileName(FileBaseName, Extension)); + + LastFilePath = filePath; + + using (var fbxExporter = Create()) + { + // ensure output directory exists + EnsureDirectory(filePath); + + if (fbxExporter.ExportAll(objects) > 0) + { + string message = string.Format("Successfully exported: {0}", filePath); + Log.Out(message); + } + else + { + Log.Warning("Nothing exported!"); + } + } + } + + private static void EnsureDirectory(string path) + { + //check to make sure the path exists, and if it doesn't then + //create all the missing directories. + FileInfo fileInfo = new FileInfo(path); + + if (!fileInfo.Exists) + { + Directory.CreateDirectory(fileInfo.Directory.FullName); + } + } +} diff --git a/Scripts/Global/CustomEnums.cs b/Scripts/Global/CustomEnums.cs new file mode 100644 index 0000000..a3dea1b --- /dev/null +++ b/Scripts/Global/CustomEnums.cs @@ -0,0 +1,28 @@ +public static class CustomEnums +{ + #region Triggers + public static MinEventTypes onSelfMagzineDeplete; + public static MinEventTypes onReloadAboutToStart; + public static MinEventTypes onRechargeValueUpdate; + public static MinEventTypes onSelfItemSwitchMode; + public static MinEventTypes onSelfBurstModeChanged; + public static MinEventTypes onSelfFirstCVarSync; + public static MinEventTypes onSelfHoldingItemAssemble; + #endregion + + #region Passives + public static PassiveEffects ReloadSpeedRatioFPV2TPV; + public static PassiveEffects RecoilSnappiness; + public static PassiveEffects RecoilReturnSpeed; + //public static PassiveEffects ProjectileImpactDamagePercentEntity; + //public static PassiveEffects ProjectileImpactDamagePercentBlock; + public static PassiveEffects PartialReloadCount; + public static PassiveEffects CustomTaggedEffect; + public static PassiveEffects KickDegreeHorizontalModifier; + public static PassiveEffects KickDegreeVerticalModifier; + public static PassiveEffects WeaponErgonomics; + public static PassiveEffects RecoilCameraShakeStrength; + public static PassiveEffects BurstShotInterval; + public static PassiveEffects MaxWeaponSpread; + #endregion +} diff --git a/Scripts/Input/PlayerActionKFLib.cs b/Scripts/Input/PlayerActionKFLib.cs new file mode 100644 index 0000000..252be6e --- /dev/null +++ b/Scripts/Input/PlayerActionKFLib.cs @@ -0,0 +1,46 @@ +using InControl; + +public class PlayerActionKFLib : CustomPlayerActionVersionBase +{ + public static PlayerActionKFLib Instance { get; private set; } + public override ControllerActionType ControllerActionDisplay => ControllerActionType.OnFoot; + + public PlayerAction ToggleFireMode; + public PlayerAction ToggleActionMode; + public PlayerAction ToggleZoom; + + public PlayerActionKFLib() + { + Name = "KFLibPlayerActions"; + Version = 1; + Instance = this; + Enabled = true; + var localActions = Platform.PlatformManager.NativePlatform.Input.PrimaryPlayer; + var permaActions = localActions.PermanentActions; + UserData = new PlayerActionData.ActionSetUserData(new PlayerActionsBase[] { localActions, permaActions }); + localActions.AddUniConflict(this); + permaActions.AddUniConflict(this); + } + + public override void CreateActions() + { + ToggleFireMode = CreatePlayerAction("ToggleFireMode"); + ToggleFireMode.UserData = new PlayerActionData.ActionUserData("inpActToggleFireModeName", "inpActToggleFireModeDesc", PlayerActionData.GroupPlayerControl); + ToggleActionMode = CreatePlayerAction("ToggleMode"); + ToggleActionMode.UserData = new PlayerActionData.ActionUserData("inpActToggleWeaponModeName", "inpActToggleWeaponModeDesc", PlayerActionData.GroupPlayerControl); + ToggleZoom = CreatePlayerAction("ToggleZoomLevel"); + ToggleZoom.UserData = new PlayerActionData.ActionUserData("inpActToggleZoomLevelName", "inpActToggleZoomLevelDesc", PlayerActionData.GroupPlayerControl); + } + + public override void CreateDefaultJoystickBindings() + { + + } + + public override void CreateDefaultKeyboardBindings() + { + ToggleFireMode.AddDefaultBinding(new Key[] { Key.Z }); + ToggleActionMode.AddDefaultBinding(new Key[] { Key.X }); + ToggleZoom.AddDefaultBinding(Mouse.MiddleButton); + } +} \ No newline at end of file diff --git a/Scripts/Input/PlayerActionToggleFireMode.cs b/Scripts/Input/PlayerActionToggleFireMode.cs new file mode 100644 index 0000000..1a3d56c --- /dev/null +++ b/Scripts/Input/PlayerActionToggleFireMode.cs @@ -0,0 +1,38 @@ +using InControl; + +public class PlayerActionToggleFireMode : CustomPlayerActionVersionBase +{ + public static PlayerActionToggleFireMode Instance { get; private set; } + public override ControllerActionType ControllerActionDisplay => ControllerActionType.OnFoot; + + public PlayerAction Toggle; + + public PlayerActionToggleFireMode() + { + Name = "ToggleFireMode"; + Version = 1; + Instance = this; + Enabled = true; + var localActions = Platform.PlatformManager.NativePlatform.Input.PrimaryPlayer; + var permaActions = localActions.PermanentActions; + UserData = new PlayerActionData.ActionSetUserData(new PlayerActionsBase[] { localActions, permaActions }); + localActions.AddUniConflict(this); + permaActions.AddUniConflict(this); + } + + public override void CreateActions() + { + Toggle = CreatePlayerAction("ToggleFireMode"); + Toggle.UserData = new PlayerActionData.ActionUserData("inpActToggleFireModeName", "inpActToggleFireModeDesc", PlayerActionData.GroupPlayerControl); + } + + public override void CreateDefaultJoystickBindings() + { + + } + + public override void CreateDefaultKeyboardBindings() + { + Toggle.AddDefaultBinding(new Key[] { Key.Z }); + } +} diff --git a/Scripts/Input/PlayerActionToggleMode.cs b/Scripts/Input/PlayerActionToggleMode.cs new file mode 100644 index 0000000..6674983 --- /dev/null +++ b/Scripts/Input/PlayerActionToggleMode.cs @@ -0,0 +1,38 @@ +using InControl; + +public class PlayerActionToggleMode : CustomPlayerActionVersionBase +{ + public static PlayerActionToggleMode Instance { get; private set; } + public override ControllerActionType ControllerActionDisplay => ControllerActionType.OnFoot; + + public PlayerAction Toggle; + + public PlayerActionToggleMode() + { + Name = "WeaponMode"; + Version = 1; + Instance = this; + Enabled = true; + var localActions = Platform.PlatformManager.NativePlatform.Input.PrimaryPlayer; + var permaActions = localActions.PermanentActions; + UserData = new PlayerActionData.ActionSetUserData(new PlayerActionsBase[] { localActions, permaActions }); + localActions.AddUniConflict(this); + permaActions.AddUniConflict(this); + } + + public override void CreateActions() + { + Toggle = CreatePlayerAction("ToggleMode"); + Toggle.UserData = new PlayerActionData.ActionUserData("inpActToggleWeaponModeName", "inpActToggleWeaponModeDesc", PlayerActionData.GroupPlayerControl); + } + + public override void CreateDefaultJoystickBindings() + { + + } + + public override void CreateDefaultKeyboardBindings() + { + Toggle.AddDefaultBinding(new Key[] { Key.X }); + } +} diff --git a/Scripts/Items/ItemActionAltMode.cs b/Scripts/Items/ItemActionAltMode.cs new file mode 100644 index 0000000..ad7cc30 --- /dev/null +++ b/Scripts/Items/ItemActionAltMode.cs @@ -0,0 +1,208 @@ +using System.Collections.Generic; +using System.Xml.Linq; +using UnityEngine; + +public class ItemActionAltMode : ItemActionHoldOpen +{ + protected string cvarStateSwitch = null; + protected bool[] altInfiniteAmmo = null; + protected bool originalInfiniteAmmo = false; + private string altModeAnimatorBool = "altMode"; + protected List[] altRequirements; + + public int getCurAltIndex(EntityAlive holdingEntity) + { + return MathUtils.Max((int)holdingEntity.GetCVar(cvarStateSwitch), 0) - 1; + } + + public virtual void setAltSound(ItemActionData _actionData) + { + ItemActionDataAltMode _data = _actionData as ItemActionDataAltMode; + _data.SetAltSound(); + int altIndex = _data.modeIndex; + if (altIndex >= 0) + soundEmpty = _data.altSoundEmpty.Length > altIndex ? _data.altSoundEmpty[altIndex] : string.Empty; + else + soundEmpty = _data.originalSoundEmpty; + } + + public override void OnModificationsChanged(ItemActionData _data) + { + base.OnModificationsChanged(_data); + var _dataAlt = _data as ItemActionDataAltMode; + + string originalValue = ""; + Properties.ParseString("Sound_start", ref originalValue); + _dataAlt.originalSoundStart = _dataAlt.invData.itemValue.GetPropertyOverride("Sound_start", originalValue); + if (_dataAlt.originalSoundStart.Contains("silenced")) + _dataAlt.suppressFlashOnOrigin = true; + + originalValue = ""; + Properties.ParseString("Sound_loop", ref originalValue); + _dataAlt.originalSoundLoop = _dataAlt.invData.itemValue.GetPropertyOverride("Sound_loop", originalValue); + + originalValue = ""; + Properties.ParseString("Sound_end", ref originalValue); + _dataAlt.originalSoundEnd = _dataAlt.invData.itemValue.GetPropertyOverride("Sound_end", originalValue); + + originalValue = ""; + Properties.ParseString("Sound_empty", ref originalValue); + _dataAlt.originalSoundEmpty = _dataAlt.invData.itemValue.GetPropertyOverride("Sound_empty", originalValue); + + + string _altString = string.Empty; + Properties.ParseString("Alt_Sound_Start", ref _altString); + _altString = _dataAlt.invData.itemValue.GetPropertyOverride("Alt_Sound_Start", _altString); + _dataAlt.altSoundStart = _altString.Split(','); + _dataAlt.suppressFlashOnAlt = new bool[_dataAlt.altSoundStart.Length]; + for (int i = 0; i < _dataAlt.suppressFlashOnAlt.Length; ++i) + { + if (_dataAlt.altSoundStart[i].Contains("silenced")) + _dataAlt.suppressFlashOnAlt[i] = true; + } + + _altString = string.Empty; + Properties.ParseString("Alt_Sound_Loop", ref _altString); + _altString = _dataAlt.invData.itemValue.GetPropertyOverride("Alt_Sound_Loop", _altString); + _dataAlt.altSoundLoop = _altString.Split(','); + + _altString = string.Empty; + Properties.ParseString("Alt_Sound_End", ref _altString); + _altString = _dataAlt.invData.itemValue.GetPropertyOverride("Alt_Sound_End", _altString); + _dataAlt.altSoundEnd = _altString.Split(','); + + _altString = string.Empty; + Properties.ParseString("Alt_Sound_Empty", ref _altString); + _altString = _dataAlt.invData.itemValue.GetPropertyOverride("Alt_Sound_Empty", _altString); + _dataAlt.altSoundEmpty = _altString.Split(','); + } + + public override ItemActionData CreateModifierData(ItemInventoryData _invData, int _indexInEntityOfAction) + { + return new ItemActionDataAltMode(_invData, _indexInEntityOfAction, cvarStateSwitch); + } + + public override void ReadFrom(DynamicProperties _props) + { + base.ReadFrom(_props); + + string _altString = string.Empty; + _props.ParseString("Cvar_State_Switch", ref cvarStateSwitch); + _props.ParseString("Alt_InfiniteAmmo", ref _altString); + string[] _altInfiniteAmmo = _altString.Split(','); + altInfiniteAmmo = new bool[_altInfiniteAmmo.Length]; + for (int i = 0; i < altInfiniteAmmo.Length; ++i) + altInfiniteAmmo[i] = bool.Parse(_altInfiniteAmmo[i]); + originalInfiniteAmmo = InfiniteAmmo; + + altRequirements = new List[_altInfiniteAmmo.Length + 1]; + } + + public void ParseAltRequirements(XElement _node, int _actionIdx) + { + foreach (XElement elem in _node.Elements("property")) + { + if (elem.HasAttribute("class") && elem.GetAttribute("class").Contains(_actionIdx.ToString())) + { + for (int i = 0; i < altRequirements.Length; ++i) + { + var requirements = new List(); + requirements.AddRange(ExecutionRequirements); + foreach (XElement childElem in elem.Elements()) + { + if (childElem.Name.LocalName.Equals("requirements" + i)) + { + requirements.AddRange(RequirementBase.ParseRequirements(childElem)); + break; + } + } + altRequirements[i] = requirements; + } + break; + } + } + } + + public void SetAltRequirement(ItemActionData _actionData) + { + if (_actionData is ItemActionDataAltMode _data) + ExecutionRequirements = altRequirements[_data.modeIndex + 1]; + } + + public override void ExecuteAction(ItemActionData _actionData, bool _bReleased) + { + ItemActionDataAltMode _data = _actionData as ItemActionDataAltMode; + int curAltIndex = _data.modeIndex; + + if (!_bReleased && curAltIndex >= 0) + InfiniteAmmo = altInfiniteAmmo.Length > curAltIndex ? altInfiniteAmmo[curAltIndex] : false; + else + InfiniteAmmo = originalInfiniteAmmo; + base.ExecuteAction(_actionData, _bReleased); + } + + public override void ItemActionEffects(GameManager _gameManager, ItemActionData _actionData, int _firingState, Vector3 _startPos, Vector3 _direction, int _userData = 0) + { + if (_firingState != 0) + setAltSound(_actionData); + base.ItemActionEffects(_gameManager, _actionData, _firingState, _startPos, _direction, _userData); + } + + public override void OnHoldingUpdate(ItemActionData _actionData) + { + base.OnHoldingUpdate(_actionData); + + if (GameManager.IsDedicatedServer || !(_actionData is ItemActionDataAltMode _data)) + return; + + EntityAlive holdingEntity = _data.invData.holdingEntity; + + int altIndex = getCurAltIndex(holdingEntity); + if (altIndex != _data.modeIndex) + { + if (_data.modeIndex >= 0) + setAnimatorBool(holdingEntity, altModeAnimatorBool + (_data.modeIndex + 1).ToString(), false); + if (altIndex >= 0) + setAnimatorBool(holdingEntity, altModeAnimatorBool + (altIndex + 1).ToString(), true); + _data.modeIndex = altIndex; + } + } + + public class ItemActionDataAltMode : ItemActionDataRanged + { + public ItemActionDataAltMode(ItemInventoryData _invData, int _indexInEntityOfAction, string cvar_switch) : base(_invData, _indexInEntityOfAction) + { + } + + public void SetAltSound() + { + if (modeIndex >= 0) + { + SoundStart = altSoundStart.Length > modeIndex ? altSoundStart[modeIndex] : string.Empty; + SoundLoop = altSoundLoop.Length > modeIndex ? altSoundLoop[modeIndex] : string.Empty; + SoundEnd = altSoundEnd.Length > modeIndex ? altSoundEnd[modeIndex] : string.Empty; + IsFlashSuppressed = suppressFlashOnAlt.Length > modeIndex ? suppressFlashOnAlt[modeIndex] : false; + } + else + { + SoundStart = originalSoundStart; + SoundLoop = originalSoundLoop; + SoundEnd = originalSoundEnd; + IsFlashSuppressed = suppressFlashOnOrigin; + } + } + + public int modeIndex = -1; + public string originalSoundStart = string.Empty; + public string originalSoundLoop = string.Empty; + public string originalSoundEnd = string.Empty; + public string originalSoundEmpty = string.Empty; + public string[] altSoundStart = null; + public string[] altSoundLoop = null; + public string[] altSoundEnd = null; + public string[] altSoundEmpty = null; + public bool suppressFlashOnOrigin = false; + public bool[] suppressFlashOnAlt; + } +} + diff --git a/Scripts/Items/ItemActionHoldOpen.cs b/Scripts/Items/ItemActionHoldOpen.cs new file mode 100644 index 0000000..38a3d9a --- /dev/null +++ b/Scripts/Items/ItemActionHoldOpen.cs @@ -0,0 +1,172 @@ +using System.Collections; +using UnityEngine; + +public class ItemActionHoldOpen : ItemActionRanged +{ + private const string emptyAnimatorBool = "empty"; + //private EntityAlive lastHoldingEntity = null; + //private HashSet hashset_dirty = new HashSet(); + //private bool reloadReset = false; + + public Animator getAnimator(EntityAlive holdingEntity) + { + Animator animator = null; + //should not use ?. here because when you use something from bag ui entry, the holding item is destroyed but still referenced in the avatar controller + //and ?. will try to access that reference instead of return null and throw NRE, while != in unity is override to return null in such case + if (holdingEntity.emodel.avatarController is AvatarMultiBodyController multiBody && multiBody.HeldItemAnimator != null) + animator = multiBody.HeldItemAnimator; + else if (holdingEntity.emodel.avatarController is LegacyAvatarController legacy && legacy.HeldItemTransform != null) + animator = legacy.HeldItemTransform.GetComponent(); + return animator; + } + + public void setAnimatorBool(EntityAlive holdingEntity, string parameter, bool flag) + { + holdingEntity.emodel.avatarController.UpdateBool(parameter, flag, false); + //Animator animator = getAnimator(holdingEntity); + //if (animator) + //{ + // animator.SetBool(parameter, flag); + // //Log.Out("trying to set param: " + parameter + " flag: " + flag + " result: " + getAnimatorBool(holdingEntity, parameter) + " transform: " + animator.transform.name); + //} + } + + public void setAnimatorFloat(EntityAlive holdingEntity, string parameter, float value) + { + holdingEntity.emodel.avatarController.UpdateFloat(parameter, value, false); + //Animator animator = getAnimator(holdingEntity); + //if (animator) + //{ + // animator.SetFloat(parameter, value); + // //Log.Out("trying to set param: " + parameter + " flag: " + flag + " result: " + getAnimatorBool(holdingEntity, parameter) + " transform: " + animator.transform.name); + //} + } + + public override int getUserData(ItemActionData _actionData) + { + return _actionData.invData.itemValue.Meta <= 0 ? 1 : 0; + } + + public override void ItemActionEffects(GameManager _gameManager, ItemActionData _actionData, int _firingState, Vector3 _startPos, Vector3 _direction, int _userData = 0) + { + base.ItemActionEffects(_gameManager, _actionData, _firingState, _startPos, _direction, _userData); + + if (_firingState != (int)ItemActionFiringState.Off && (_userData & 1) > 0) + setAnimatorBool(_actionData.invData.holdingEntity, emptyAnimatorBool, true); + } + + public override void ReloadGun(ItemActionData _actionData) + { + base.ReloadGun(_actionData); + //delay 2 frames before reloading, since the animation is likely to be triggered the next frame this is called + ThreadManager.StartCoroutine(DelaySetEmpty(_actionData, false, 2)); + //reloadReset = true; + } + + public override void StartHolding(ItemActionData _data) + { + //reloadReset = false; + //if(_data.invData.itemValue.Meta <= 0) + // hashset_dirty.Add(_data.invData.holdingEntity); + //lastHoldingEntity = _data.invData.holdingEntity; + //lastHoldingEntity.inventory.OnToolbeltItemsChangedInternal += OnStartHolding; + //delay 1 frame before equipping weapon + if (_data.invData.itemValue.Meta <= 0) + ThreadManager.StartCoroutine(DelaySetEmpty(_data, true, 1)); + base.StartHolding(_data); + } + + //protected virtual void OnStartHolding() + //{ + // if(lastHoldingEntity.inventory.holdingItemItemValue.Meta <= 0) + // setAnimatorBool(lastHoldingEntity, emptyAnimatorBool, true); + // //hashset_dirty.Add(lastHoldingEntity); + // //Log.Out("Entity " + lastHoldingEntity.entityId + " start holding " + lastHoldingEntity.inventory.holdingItemItemValue.ItemClass.Name + " meta: " + lastHoldingEntity.inventory.holdingItemItemValue.Meta); + // lastHoldingEntity.inventory.OnToolbeltItemsChangedInternal -= OnStartHolding; + // lastHoldingEntity = null; + //} + + public override void ConsumeAmmo(ItemActionData _actionData) + { + base.ConsumeAmmo(_actionData); + if (_actionData.invData.itemValue.Meta == 0) + _actionData.invData.holdingEntity.FireEvent(CustomEnums.onSelfMagzineDeplete, true); + } + + public override void SwapAmmoType(EntityAlive _entity, int _ammoItemId = -1) + { + setAnimatorBool(_entity, emptyAnimatorBool, true); + base.SwapAmmoType(_entity, _ammoItemId); + /* + ItemActionDataRanged _action = _entity.inventory.holdingItemData.actionData[0] as ItemActionDataRanged; + Log.Out("is reloading: " + _action.isReloading + " item: " + _action.invData.itemValue.ItemClass.Name + " meta: " + _action.invData.itemValue.Meta + " holding item: " + _entity.inventory.holdingItemItemValue.ItemClass.Name + " holding meta: " + _entity.inventory.holdingItemItemValue.Meta); + if (_action != null && !_action.isReloading && _action.invData.itemValue.Meta <= 0) + */ + } + + private IEnumerator DelaySetEmpty(ItemActionData _actionData, bool empty, int delay) + { + for (int i = 0; i < delay; i++) + { + yield return null; + } + if (_actionData.invData.holdingEntity.inventory.holdingItemIdx == _actionData.invData.slotIdx) + { + setAnimatorBool(_actionData.invData.holdingEntity, emptyAnimatorBool, empty); + } + yield break; + } + + //public override void OnHoldingUpdate(ItemActionData _actionData) + //{ + // base.OnHoldingUpdate(_actionData); + + // if (GameManager.IsDedicatedServer) + // return; + + // if (reloadReset) + // { + // setAnimatorBool(GameManager.Instance.World.GetPrimaryPlayer(), emptyAnimatorBool, false); + // reloadReset = false; + // } + + // if (hashset_dirty.Count <= 0) + // return; + + // foreach (EntityAlive holdingEntity in hashset_dirty) + // setAnimatorBool(holdingEntity, emptyAnimatorBool, true); + // hashset_dirty.Clear(); + // /* + // EntityAlive holdingEntity = _actionData.invData.holdingEntity; + // if (hash_dirty.Count <= 0 || !hash_dirty.ContainsKey(holdingEntity)) + // return; + + // if (hash_dirty[holdingEntity]) + // hash_dirty[holdingEntity] = false; + // else + // { + // hash_dirty.Remove(holdingEntity); + // setAnimatorBool(holdingEntity, emptyAnimatorBool, true); + // } + // */ + // /* + // EntityAlive holdingEntity = _actionData.invData.holdingEntity; + // bool isReloading = (_actionData as ItemActionDataRanged).isReloading; + // if (holdingEntity.isEntityRemote && !isReloading) + // return; + // int meta = _actionData.invData.itemValue.Meta; + // if (!isReloading && meta <= 0 && !getAnimatorBool(holdingEntity, emptyAnimatorBool)) + // { + // Log.Out("trying to update param: " + emptyAnimatorBool + " flag: " + true); + // setAnimatorBool(holdingEntity, emptyAnimatorBool, true); + // } + // else if ((isReloading || meta > 0) && getAnimatorBool(holdingEntity, emptyAnimatorBool)) + // { + // Log.Out("trying to update param: " + emptyAnimatorBool + " flag: " + false); + // setAnimatorBool(holdingEntity, emptyAnimatorBool, false); + // } + // */ + //} + +} + diff --git a/Scripts/Items/ItemActionRampUp.cs b/Scripts/Items/ItemActionRampUp.cs new file mode 100644 index 0000000..2c7c158 --- /dev/null +++ b/Scripts/Items/ItemActionRampUp.cs @@ -0,0 +1,188 @@ +using Audio; +using KFCommonUtilityLib.Scripts.Utilities; +using System; +using UnityEngine; + +public class ItemActionRampUp : ItemActionHoldOpen +{ + public override void ExecuteAction(ItemActionData _actionData, bool _bReleased) + { + var _rampData = _actionData as ItemActionDataRampUp; + if (!_bReleased && (InfiniteAmmo || _actionData.invData.itemValue.Meta > 0) && _actionData.invData.itemValue.PercentUsesLeft > 0) + { + _rampData.bReleased = false; + if (!_rampData.prepareStarted) + _rampData.invData.gameManager.ItemActionEffectsServer(_rampData.invData.holdingEntity.entityId, _rampData.invData.slotIdx, _rampData.indexInEntityOfAction, 0, Vector3.zero, Vector3.zero, 4); + + if (Time.time - _rampData.prepareStartTime < _rampData.prepareTime) + return; + } + base.ExecuteAction(_actionData, _bReleased); + } + + public override void ItemActionEffects(GameManager _gameManager, ItemActionData _actionData, int _firingState, Vector3 _startPos, Vector3 _direction, int _userData = 0) + { + base.ItemActionEffects(_gameManager, _actionData, _firingState, _startPos, _direction, _userData); + var _rampData = _actionData as ItemActionDataRampUp; + var entity = _rampData.invData.holdingEntity; + if (_firingState != 0) + { + if ((_userData & 2) > 0) + { + Manager.Stop(entity.entityId, _rampData.rampSound); + _rampData.rampStarted = true; + _rampData.rampStartTime = Time.time; + Manager.Play(entity, _rampData.rampSound); + } + } + else if ((_userData & 4) > 0) + { + //Log.Out("released, try aim charge!" + _userData); + ResetRamp(_rampData); + if (!_rampData.prepareStarted) + { + //Log.Out("released and aim charge!"); + Manager.Stop(entity.entityId, _rampData.prepareSound); + _rampData.prepareStarted = true; + _rampData.prepareStartTime = Time.time; + Manager.Play(entity, _rampData.prepareSound); + setAnimatorBool(_rampData.invData.holdingEntity, "prepare", true); + setAnimatorFloat(_rampData.invData.holdingEntity, "prepareSpeed", _rampData.prepareSpeed); + } + } + else + { + //Log.Out("released, reset all!" + _userData + entity.AimingGun); + ResetAll(_rampData); + } + } + + public override int getUserData(ItemActionData _actionData) + { + var _rampData = _actionData as ItemActionDataRampUp; + return base.getUserData(_actionData) | (Convert.ToInt32(_rampData.curBurstCount == _rampData.minRampShots) << 1) | (Convert.ToInt32(_rampData.zoomPrepare && _rampData.invData.holdingEntity.AimingGun) << 2); + } + + public override void OnHoldingUpdate(ItemActionData _actionData) + { + base.OnHoldingUpdate(_actionData); + var _rampData = _actionData as ItemActionDataRampUp; + if (_rampData.invData.holdingEntity.isEntityRemote) + return; + + bool aiming = _rampData.invData.holdingEntity.AimingGun; + if (!_rampData.prepareStarted && _rampData.zoomPrepare && aiming) + { + _rampData.invData.gameManager.ItemActionEffectsServer(_rampData.invData.holdingEntity.entityId, _rampData.invData.slotIdx, _rampData.indexInEntityOfAction, 0, Vector3.zero, Vector3.zero, 4); + //Log.Out("Aim charge!"); + } + else if (_rampData.prepareStarted && _rampData.bReleased && (!_rampData.zoomPrepare || !aiming)) + { + _rampData.invData.gameManager.ItemActionEffectsServer(_rampData.invData.holdingEntity.entityId, _rampData.invData.slotIdx, _rampData.indexInEntityOfAction, 0, Vector3.zero, Vector3.zero, 0); + //Log.Out("Stop charge!"); + } + else if (_rampData.rampStarted) + { + float rampElapsed = Time.time - _rampData.rampStartTime; + if (rampElapsed > 0) + _rampData.Delay /= rampElapsed > _rampData.rampTime ? _rampData.maxMultiplier : rampElapsed * (_rampData.maxMultiplier - 1) / _rampData.rampTime + 1; + } + } + + public override void StopHolding(ItemActionData _data) + { + base.StopHolding(_data); + var _rampData = _data as ItemActionDataRampUp; + ResetRamp(_rampData); + } + + public override void ReloadGun(ItemActionData _actionData) + { + base.ReloadGun(_actionData); + var _rampData = _actionData as ItemActionDataRampUp; + ResetRamp(_rampData); + } + + private void ResetAll(ItemActionDataRampUp _rampData) + { + ResetPrepare(_rampData); + ResetRamp(_rampData); + //Log.Out("Reset all!"); + } + + private void ResetPrepare(ItemActionDataRampUp _rampData) + { + _rampData.prepareStarted = false; + Manager.Stop(_rampData.invData.holdingEntity.entityId, _rampData.prepareSound); + setAnimatorBool(_rampData.invData.holdingEntity, "prepare", false); + //Log.Out("Reset Prepare!"); + } + + private void ResetRamp(ItemActionDataRampUp _rampData) + { + _rampData.rampStarted = false; + Manager.Stop(_rampData.invData.holdingEntity.entityId, _rampData.rampSound); + //Log.Out("Reset Ramp!"); + } + + public override ItemActionData CreateModifierData(ItemInventoryData _invData, int _indexInEntityOfAction) + { + return new ItemActionDataRampUp(_invData, _indexInEntityOfAction); + } + + public override void OnModificationsChanged(ItemActionData _data) + { + base.OnModificationsChanged(_data); + var _rampData = _data as ItemActionDataRampUp; + string originalValue = 1.ToString(); + Properties.ParseString("RampMultiplier", ref originalValue); + _rampData.maxMultiplier = Mathf.Max(float.Parse(_rampData.invData.itemValue.GetPropertyOverrideForAction("RampMultiplier", originalValue, _data.indexInEntityOfAction)), 0); + + originalValue = 0.ToString(); + Properties.ParseString("RampTime", ref originalValue); + _rampData.rampTime = float.Parse(_rampData.invData.itemValue.GetPropertyOverrideForAction("RampTime", originalValue, _data.indexInEntityOfAction)); + + originalValue = 1.ToString(); + Properties.ParseString("MinRampShots", ref originalValue); + _rampData.minRampShots = Mathf.Max(int.Parse(_rampData.invData.itemValue.GetPropertyOverrideForAction("MinRampShots", originalValue, _data.indexInEntityOfAction)), 1); + + originalValue = string.Empty; + Properties.ParseString("RampStartSound", ref originalValue); + _rampData.rampSound = _rampData.invData.itemValue.GetPropertyOverrideForAction("RampStartSound", originalValue, _data.indexInEntityOfAction); + + originalValue = 0.ToString(); + Properties.ParseString("PrepareTime", ref originalValue); + _rampData.prepareTime = float.Parse(_rampData.invData.itemValue.GetPropertyOverrideForAction("PrepareTime", originalValue, _data.indexInEntityOfAction)); + _rampData.prepareSpeed = float.Parse(originalValue) / _rampData.prepareTime; + + originalValue = string.Empty; + Properties.ParseString("PrepareSound", ref originalValue); + _rampData.prepareSound = _rampData.invData.itemValue.GetPropertyOverrideForAction("PrepareSound", originalValue, _data.indexInEntityOfAction); + + originalValue = false.ToString(); + Properties.ParseString("PrepareOnAim", ref originalValue); + _rampData.zoomPrepare = bool.Parse(_rampData.invData.itemValue.GetPropertyOverrideForAction("PrepareOnAim", originalValue, _data.indexInEntityOfAction)); + } + + public class ItemActionDataRampUp : ItemActionDataRanged + { + public ItemActionDataRampUp(ItemInventoryData _invData, int _indexInEntityOfAction) : base(_invData, _indexInEntityOfAction) + { + } + + public float maxMultiplier = 1f; + public float rampTime = 0f; + public float prepareTime = 0f; + public float prepareSpeed = 1f; + public string rampSound = string.Empty; + public string prepareSound = string.Empty; + public int minRampShots = 1; + + public float rampStartTime = 0f; + public bool rampStarted = false; + public float prepareStartTime = 0f; + public bool prepareStarted = false; + public bool zoomPrepare = false; + } +} + diff --git a/Scripts/Items/ItemActionRechargeable.cs b/Scripts/Items/ItemActionRechargeable.cs new file mode 100644 index 0000000..42fa850 --- /dev/null +++ b/Scripts/Items/ItemActionRechargeable.cs @@ -0,0 +1,76 @@ +public class ItemActionRechargeable : ItemActionAltMode +{ + protected string[] cvarToConsume = null; + protected string[] cvarConsumption = null; + protected string[] cvarNoConsumptionTemp = null; + + public override void ReadFrom(DynamicProperties _props) + { + base.ReadFrom(_props); + + string _altString = string.Empty; + _props.ParseString("Cvar_To_Consume", ref _altString); + cvarToConsume = _altString.Split(','); + _altString = string.Empty; + _props.ParseString("Cvar_Consumption", ref _altString); + cvarConsumption = _altString.Split(','); + if (cvarToConsume.Length != cvarConsumption.Length) + Log.Error("cvar to consume count does not match cvar consumption count!"); + _altString = string.Empty; + _props.ParseString("Cvar_No_Consumption_Burst_Count", ref _altString); + cvarNoConsumptionTemp = _altString.Split(','); + } + + public override void ExecuteAction(ItemActionData _actionData, bool _bReleased) + { + ItemActionDataAltMode _data = _actionData as ItemActionDataAltMode; + EntityAlive holdingEntity = _data.invData.holdingEntity; + ItemValue itemValue = _data.invData.itemValue; + if (!_bReleased) + { + int curAltIndex = _data.modeIndex; + if (curAltIndex >= 0) + InfiniteAmmo = altInfiniteAmmo.Length > curAltIndex ? altInfiniteAmmo[curAltIndex] : false; + else + InfiniteAmmo = originalInfiniteAmmo; + + int burstCount = GetBurstCount(_actionData); + if ((_data.curBurstCount >= burstCount && burstCount != -1) || (!InfiniteAmmo && itemValue.Meta <= 0)) + { + base.ExecuteAction(_actionData, _bReleased); + return; + } + + if (curAltIndex >= 0 && cvarConsumption.Length > curAltIndex && !string.IsNullOrEmpty(cvarConsumption[curAltIndex])) + { + float consumption = holdingEntity.GetCVar(cvarConsumption[curAltIndex]); + if (cvarNoConsumptionTemp.Length > curAltIndex && !string.IsNullOrEmpty(cvarNoConsumptionTemp[curAltIndex])) + { + float isConsumption0 = holdingEntity.GetCVar(cvarNoConsumptionTemp[curAltIndex]); + if (isConsumption0 > 0) + { + consumption = 0; + holdingEntity.SetCVar(cvarNoConsumptionTemp[curAltIndex], --isConsumption0); + } + } + + float stock = holdingEntity.GetCVar(cvarToConsume[curAltIndex]); + if (stock < consumption) + { + holdingEntity.PlayOneShot(_data.altSoundEmpty.Length >= curAltIndex ? _data.altSoundEmpty[curAltIndex] : _data.originalSoundEmpty); + return; + } + + if (holdingEntity.inventory.holdingItemItemValue.PercentUsesLeft > 0f) + { + float left = stock - consumption; + holdingEntity.SetCVar(cvarToConsume[curAltIndex], left); + } + base.ExecuteAction(_actionData, _bReleased); + return; + } + } + base.ExecuteAction(_actionData, _bReleased); + } +} + diff --git a/Scripts/Items/Modular/ActionModuleAlternative.cs b/Scripts/Items/Modular/ActionModuleAlternative.cs new file mode 100644 index 0000000..abc647f --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleAlternative.cs @@ -0,0 +1,261 @@ +using GUI_2; +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; +using System.Collections; +using Unity.Mathematics; + +[TypeTarget(typeof(ItemActionAttack)), ActionDataTarget(typeof(AlternativeData))] +public class ActionModuleAlternative +{ + internal static ItemValue InventorySetItemTemp; + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPrefix] + private bool Prefix_StartHolding(ItemActionData _data, AlternativeData __customData) + { + //__customData.Init(); + int prevMode = __customData.mapping.CurMode; + __customData.UpdateUnlockState(_data.invData.itemValue); + if (prevMode != __customData.mapping.CurMode && _data.invData.holdingEntity is EntityPlayerLocal player) + { + MultiActionManager.FireToggleModeEvent(player, __customData.mapping); + } + MultiActionManager.SetMappingForEntity(_data.invData.holdingEntity.entityId, __customData.mapping); + if (_data.invData.holdingEntity is EntityPlayerLocal) + { + MultiActionManager.inputCD = math.max(0.5f, MultiActionManager.inputCD); + //ThreadManager.StartCoroutine(DelaySetExecutionIndex(_data.invData.holdingEntity, __customData.mapping)); + } + return true; + } + + //[MethodTargetPostfix(nameof(ItemActionAttack.StartHolding))] + //private void Postfix_StartHolding(AlternativeData __customData) + //{ + // __customData.UpdateMuzzleTransformOverride(); + // __customData.OverrideMuzzleTransform(__customData.mapping.CurMode); + //} + + private static IEnumerator DelaySetExecutionIndex(EntityAlive player, MultiActionMapping mapping) + { + yield return null; + yield return null; + if (GameManager.Instance.GetGameStateManager().IsGameStarted()) + player?.emodel?.avatarController?.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, mapping.CurActionIndex); + } + + [HarmonyPatch(nameof(ItemActionRanged.CancelReload)), MethodTargetPrefix] + private bool Prefix_CancelReload(ItemActionData _actionData, AlternativeData __customData) + { + if (__customData.mapping == null) + return true; + int actionIndex = __customData.mapping.CurActionIndex; + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"cancel reload {actionIndex}"); + if (actionIndex == 0) + return true; + _actionData.invData.holdingEntity.inventory.holdingItem.Actions[actionIndex].CancelReload(_actionData.invData.holdingEntity.inventory.holdingItemData.actionData[actionIndex]); + return false; + } + + [HarmonyPatch(nameof(ItemAction.CancelAction)), MethodTargetPrefix] + private bool Prefix_CancelAction(ItemActionData _actionData, AlternativeData __customData) + { + if (__customData.mapping == null) + return true; + int actionIndex = __customData.mapping.CurActionIndex; + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"cancel action {actionIndex}"); + if (actionIndex == 0) + return true; + _actionData.invData.holdingEntity.inventory.holdingItem.Actions[actionIndex].CancelAction(_actionData.invData.holdingEntity.inventory.holdingItemData.actionData[actionIndex]); + return false; + } + + [HarmonyPatch(nameof(ItemAction.IsStatChanged)), MethodTargetPrefix] + private bool Prefix_IsStatChanged(ref bool __result) + { + var mapping = MultiActionManager.GetMappingForEntity(GameManager.Instance.World.GetPrimaryPlayerId()); + __result |= mapping != null && mapping.CheckDisplayMode(); + return false; + } + + //[MethodTargetPostfix(nameof(ItemActionAttack.StopHolding))] + //private void Postfix_StopHolding(AlternativeData __customData) + //{ + // //moved to harmony patch + // //MultiActionManager.SetMappingForEntity(_data.invData.holdingEntity.entityId, null); + // __customData.mapping.SaveMeta(); + //} + + //todo: change to action specific property + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationChanged(ItemActionData _data, ItemActionAttack __instance, AlternativeData __customData) + { + __instance.Properties.ParseString("ToggleActionSound", ref __customData.toggleSound); + __customData.toggleSound = _data.invData.itemValue.GetPropertyOverrideForAction("ToggleActionSound", __customData.toggleSound, __instance.ActionIndex); + __customData.mapping.toggleSound = __customData.toggleSound; + } + + [HarmonyPatch(nameof(ItemAction.SetupRadial)), MethodTargetPrefix] + private bool Prefix_SetupRadial(XUiC_Radial _xuiRadialWindow, EntityPlayerLocal _epl) + { + var mapping = MultiActionManager.GetMappingForEntity(_epl.entityId); + if (mapping != null) + { + var radialContextItem = new AlternativeRadialContextItem(mapping, _xuiRadialWindow, _epl); + _xuiRadialWindow.SetCommonData(UIUtils.GetButtonIconForAction(_epl.playerInput.Reload), handleRadialCommand, radialContextItem, radialContextItem.PreSelectedIndex, false, radialValidTest); + } + + return false; + } + + private bool radialValidTest(XUiC_Radial _sender, XUiC_Radial.RadialContextAbs _context) + { + AlternativeRadialContextItem radialContextItem = _context as AlternativeRadialContextItem; + if (radialContextItem == null) + { + return false; + } + EntityPlayerLocal entityPlayer = _sender.xui.playerUI.entityPlayer; + return radialContextItem.mapping == MultiActionManager.GetMappingForEntity(entityPlayer.entityId) && radialContextItem.mapping.CurActionIndex == radialContextItem.ActionIndex; + } + + //redirect reload call to shared meta action, which then sets ItemActionIndex animator param to its action index + //for example if action 3 share meta with action 0, then ItemActionIndex is set to 0 on reload begin. + //since event param item action data is set to the shared meta action data, all reload related passive calculation and trigger events goes there. + private void handleRadialCommand(XUiC_Radial _sender, int _commandIndex, XUiC_Radial.RadialContextAbs _context) + { + AlternativeRadialContextItem radialContextItem = _context as AlternativeRadialContextItem; + if (radialContextItem == null) + { + return; + } + EntityPlayerLocal entityPlayer = _sender.xui.playerUI.entityPlayer; + if (radialContextItem.mapping == MultiActionManager.GetMappingForEntity(entityPlayer.entityId) && radialContextItem.mapping.CurActionIndex == radialContextItem.ActionIndex) + { + entityPlayer.MinEventContext.ItemActionData = entityPlayer.inventory.holdingItemData.actionData?[radialContextItem.ActionIndex]; + (entityPlayer.inventory.holdingItem.Actions?[radialContextItem.ActionIndex] as ItemActionRanged)?.SwapSelectedAmmo(entityPlayer, _commandIndex); + } + } + + public class AlternativeData + { + public MultiActionMapping mapping; + public string toggleSound; + public ItemInventoryData invData; + //private bool inited = false; + private readonly bool[] unlocked = new bool[MultiActionIndice.MAX_ACTION_COUNT]; + //public Transform[] altMuzzleTrans = new Transform[MultiActionIndice.MAX_ACTION_COUNT]; + //public Transform[] altMuzzleTransDBarrel = new Transform[MultiActionIndice.MAX_ACTION_COUNT]; + + public AlternativeData(ItemInventoryData invData, int actionIndex, ActionModuleAlternative module) + { + this.invData = invData; + Init(); + + } + + //public void UpdateMuzzleTransformOverride() + //{ + // for (int i = 0; i < MultiActionIndice.MAX_ACTION_COUNT; i++) + // { + // int curActionIndex = mapping.indices.GetActionIndexForMode(i); + // if (curActionIndex < 0) + // { + // break; + // } + // var rangedData = invData.actionData[curActionIndex] as ItemActionRanged.ItemActionDataRanged; + // if (rangedData != null) + // { + // if (rangedData.IsDoubleBarrel) + // { + // altMuzzleTrans[i] = AnimationRiggingManager.GetTransformOverrideByName($"Muzzle_L{curActionIndex}", rangedData.invData.model) ?? rangedData.muzzle; + // altMuzzleTransDBarrel[i] = AnimationRiggingManager.GetTransformOverrideByName($"Muzzle_R{curActionIndex}", rangedData.invData.model) ?? rangedData.muzzle2; + // } + // else + // { + // altMuzzleTrans[i] = AnimationRiggingManager.GetTransformOverrideByName($"Muzzle{curActionIndex}", rangedData.invData.model) ?? rangedData.muzzle; + // } + // } + // } + //} + + public void Init() + { + //if (inited) + // return; + + //inited = true; + MultiActionIndice indices = MultiActionManager.GetActionIndiceForItemID(invData.item.Id); + mapping = new MultiActionMapping(this, indices, invData.holdingEntity, InventorySetItemTemp, toggleSound, invData.slotIdx, unlocked); + UpdateUnlockState(InventorySetItemTemp); + } + + public void UpdateUnlockState(ItemValue itemValue) + { + //if (!inited) + // return; + unlocked[0] = true; + for (int i = 1; i < mapping.ModeCount; i++) + { + bool flag = true; + int actionIndex = mapping.indices.GetActionIndexForMode(i); + ItemAction action = itemValue.ItemClass.Actions[actionIndex]; + action.Properties.ParseBool("ActionUnlocked", ref flag); + if (bool.TryParse(itemValue.GetPropertyOverride($"ActionUnlocked_{actionIndex}", flag.ToString()), out bool overrideFlag)) + flag = overrideFlag; + unlocked[i] = flag; + } + //by the time we check unlock state, ItemValue in inventory slot might not be ready yet + mapping.SaveMeta(itemValue); + mapping.CurMode = mapping.CurMode; + mapping.ReadMeta(itemValue); + } + + public bool IsActionUnlocked(int actionIndex) + { + int mode = mapping.indices.GetModeForAction(actionIndex); + if (mode >= MultiActionIndice.MAX_ACTION_COUNT || mode < 0) + return false; + return unlocked[mode]; + } + +// public void OverrideMuzzleTransform(int mode) +// { +// var rangedData = invData.actionData[mapping.indices.GetActionIndexForMode(mode)] as ItemActionRanged.ItemActionDataRanged; +// if (rangedData != null) +// { +// if (rangedData.IsDoubleBarrel) +// { +// rangedData.muzzle = altMuzzleTrans[mode]; +// rangedData.muzzle2 = altMuzzleTransDBarrel[mode]; +// } +// else +// { +// rangedData.muzzle = altMuzzleTrans[mode]; +// } +// } +//#if DEBUG +// Log.Out($"setting muzzle transform for action {rangedData.indexInEntityOfAction} to {rangedData.muzzle.name}\n{StackTraceUtility.ExtractStackTrace()}"); +//#endif +// } + } + + //todo: don't setup for every mode, and use reload animation from shared action + public class AlternativeRadialContextItem : XUiC_Radial.RadialContextAbs + { + public MultiActionMapping mapping; + + public int ActionIndex { get; private set; } + public int PreSelectedIndex { get; private set; } + + public AlternativeRadialContextItem(MultiActionMapping mapping, XUiC_Radial _xuiRadialWindow, EntityPlayerLocal _epl) + { + this.mapping = mapping; + ActionIndex = mapping.CurActionIndex; + PreSelectedIndex = mapping.SetupRadial(_xuiRadialWindow, _epl); + } + } +} diff --git a/Scripts/Items/Modular/ActionModuleAnimationLocked.cs b/Scripts/Items/Modular/ActionModuleAnimationLocked.cs new file mode 100644 index 0000000..3d93ce9 --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleAnimationLocked.cs @@ -0,0 +1,36 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; + +[TypeTarget(typeof(ItemAction)), ActionDataTarget(typeof(AnimationLockedData))] +public class ActionModuleAnimationLocked +{ + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPostfix] + private void Postfix_StartHolding(AnimationLockedData __customData) + { + __customData.isLocked = false; + __customData.isReloadLocked = false; + } + + [HarmonyPatch(nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning(AnimationLockedData __customData, ref bool __result) + { + __result |= __customData.isLocked; + } + + [HarmonyPatch(typeof(ItemActionAttack), nameof(ItemActionAttack.CanReload)), MethodTargetPostfix] + private void Postfix_CanReload_ItemActionAttack(AnimationLockedData __customData, ref bool __result) + { + __result &= !__customData.isReloadLocked; + } + + public class AnimationLockedData + { + public bool isLocked = false; + public bool isReloadLocked = false; + + public AnimationLockedData(ItemInventoryData invData, int actionIndex, ActionModuleAnimationLocked module) + { + + } + } +} diff --git a/Scripts/Items/Modular/ActionModuleCustomAnimationDelay.cs b/Scripts/Items/Modular/ActionModuleCustomAnimationDelay.cs new file mode 100644 index 0000000..66dc1db --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleCustomAnimationDelay.cs @@ -0,0 +1,135 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using System.Collections.Generic; +using System.Reflection.Emit; +using UniLinq; +using static AnimationDelayData; + +[TypeTarget(typeof(ItemAction))] +public class ActionModuleCustomAnimationDelay +{ + [HarmonyPatch(typeof(ItemActionEat), nameof(ItemAction.OnHoldingUpdate))] + [HarmonyPatch(typeof(ItemActionGainSkill), nameof(ItemAction.OnHoldingUpdate))] + [HarmonyPatch(typeof(ItemActionLearnRecipe), nameof(ItemAction.OnHoldingUpdate))] + [HarmonyPatch(typeof(ItemActionQuest), nameof(ItemAction.OnHoldingUpdate))] + [HarmonyPatch(typeof(ItemActionEat), nameof(ItemAction.IsActionRunning))] + [HarmonyPatch(typeof(ItemActionGainSkill), nameof(ItemAction.IsActionRunning))] + [HarmonyPatch(typeof(ItemActionLearnRecipe), nameof(ItemAction.IsActionRunning))] + [HarmonyPatch(typeof(ItemActionQuest), nameof(ItemAction.IsActionRunning))] + [MethodTargetTranspiler] + private static IEnumerable Transpiler_OnHoldingUpdate(IEnumerable instructions) + { + var codes = instructions.ToList(); + var fld_delayarr = AccessTools.Field(typeof(AnimationDelayData), nameof(AnimationDelayData.AnimationDelay)); + var fld_raycast = AccessTools.Field(typeof(AnimationDelays), nameof(AnimationDelays.RayCast)); + + for (var i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_delayarr)) + { + for (int j = i + 1; j < codes.Count; j++) + { + if (codes[j].LoadsField(fld_raycast)) + { + bool flag = codes[i - 1].LoadsConstant(2f); + codes.RemoveRange(flag ? i - 1 : i, j - i + (flag ? 3 : 1)); + codes.InsertRange(flag ? i - 1 : i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.Delay)) + }); + break; + } + } + break; + } + } + + return codes; + } + + //[HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPrefix] + //private bool Prefix_OnHoldingUpdate(ItemAction __instance, ItemActionData _actionData, out AnimationDelays __state) + //{ + // __state = AnimationDelayData.AnimationDelay[_actionData.invData.item.HoldType.Value]; + // if (!__instance.UseAnimation) + // return true; + // var modifiedData = __state; + // modifiedData.RayCast = __instance.Delay; + // AnimationDelayData.AnimationDelay[_actionData.invData.item.HoldType.Value] = modifiedData; + // return true; + //} + + //[HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPostfix] + //private void Postfix_OnHoldingUpdate(ItemAction __instance, ItemActionData _actionData, AnimationDelays __state) + //{ + // if (!__instance.UseAnimation) + // return; + // AnimationDelayData.AnimationDelay[_actionData.invData.item.HoldType.Value] = __state; + //} + + //[HarmonyPatch(nameof(ItemAction.IsActionRunning)), MethodTargetPrefix] + //private bool Prefix_IsActionRunning(ItemAction __instance, ItemActionData _actionData, out AnimationDelays __state) + //{ + // __state = AnimationDelayData.AnimationDelay[_actionData.invData.item.HoldType.Value]; + // if (!__instance.UseAnimation) + // return true; + // var modifiedData = __state; + // modifiedData.RayCast = __instance.Delay * .5f; + // AnimationDelayData.AnimationDelay[_actionData.invData.item.HoldType.Value] = modifiedData; + // return true; + //} + + //[HarmonyPatch(nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + //private void Postfix_IsActionRunning(ItemAction __instance, ItemActionData _actionData, AnimationDelays __state) + //{ + // if (!__instance.UseAnimation) + // return; + // AnimationDelayData.AnimationDelay[_actionData.invData.item.HoldType.Value] = __state; + //} + + //following are fix for item use time from menu entry + //when IsActionRunning is called from coroutine which is started by menu entry, + //as OnHoldingUpdate is not called every frame, the check might yield false before item actually gets consumed, thus returning the item + //so we call OnHoldingUpdate to properly consume the item + //vanilla method on the other hand, is forcing double delay in IsActionRunning + [HarmonyPatch(typeof(ItemActionEat), nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning_ItemActionEat(ItemActionEat __instance, ItemActionData _actionData/*, AnimationDelays __state*/, bool __result) + { + //Postfix_IsActionRunning(__instance, _actionData, __state); + if (!__result && ((ItemActionEat.MyInventoryData)_actionData).bEatingStarted) + { + __instance.OnHoldingUpdate(_actionData); + } + } + + [HarmonyPatch(typeof(ItemActionGainSkill), nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning_ItemActionGainSkill(ItemActionGainSkill __instance, ItemActionData _actionData/*, AnimationDelays __state*/, bool __result) + { + //Postfix_IsActionRunning(__instance, _actionData, __state); + if (!__result && ((ItemActionGainSkill.MyInventoryData)_actionData).bReadingStarted) + { + __instance.OnHoldingUpdate(_actionData); + } + } + + [HarmonyPatch(typeof(ItemActionLearnRecipe), nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning_ItemActionLearnRecipe(ItemActionLearnRecipe __instance, ItemActionData _actionData/*, AnimationDelays __state*/, bool __result) + { + //Postfix_IsActionRunning(__instance, _actionData, __state); + if (!__result && ((ItemActionLearnRecipe.MyInventoryData)_actionData).bReadingStarted) + { + __instance.OnHoldingUpdate(_actionData); + } + } + + [HarmonyPatch(typeof(ItemActionQuest), nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning_ItemActionQuest(ItemActionQuest __instance, ItemActionData _actionData/*, AnimationDelays __state*/, bool __result) + { + //Postfix_IsActionRunning(__instance, _actionData, __state); + if (!__result && ((ItemActionQuest.MyInventoryData)_actionData).bQuestAccept) + { + __instance.OnHoldingUpdate(_actionData); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Modular/ActionModuleDisplayAsBuff.cs b/Scripts/Items/Modular/ActionModuleDisplayAsBuff.cs new file mode 100644 index 0000000..ac43cb3 --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleDisplayAsBuff.cs @@ -0,0 +1,78 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; + +public class DisplayAsBuffEntityUINotification : BuffEntityUINotification +{ + public ActionModuleDisplayAsBuff.DisplayValueType displayType = ActionModuleDisplayAsBuff.DisplayValueType.Meta; + public string displayData = string.Empty; + + public override float CurrentValue + { + get + { + EntityPlayerLocal player = GameManager.Instance.World.GetPrimaryPlayer(); + if (player == null) + return 0; + switch (displayType) + { + case ActionModuleDisplayAsBuff.DisplayValueType.Meta: + return player.inventory.holdingItemItemValue.Meta; + case ActionModuleDisplayAsBuff.DisplayValueType.MetaData: + return (float)player.inventory.holdingItemItemValue.GetMetadata(displayData); + default: + return 0; + } + } + } + + public override bool Visible => true; + + public override EnumEntityUINotificationDisplayMode DisplayMode => EnumEntityUINotificationDisplayMode.IconPlusCurrentValue; +} + +[TypeTarget(typeof(ItemActionRanged))] +public class ActionModuleDisplayAsBuff +{ + public enum DisplayValueType + { + Meta, + MetaData + } + + private DisplayAsBuffEntityUINotification notification; + private BuffClass buffClass; + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props) + { + notification = new DisplayAsBuffEntityUINotification(); + _props.Values.TryGetValue("DisplayType", out string str); + EnumUtils.TryParse(str, out notification.displayType, true); + _props.Values.TryGetValue("DisplayData", out notification.displayData); + _props.Values.TryGetValue("DisplayBuff", out str); + BuffClass buffClass = BuffManager.GetBuff(str); + BuffValue buff = new BuffValue(buffClass.Name, Vector3i.zero, -1, buffClass); + notification.SetBuff(buff); + } + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPostfix] + private void Postfix_StartHolding(ItemActionData _data) + { + EntityPlayerLocal player = _data.invData.holdingEntity as EntityPlayerLocal; + if (player != null && notification != null) + { + notification.SetStats(player.Stats); + player.Stats.NotificationAdded(notification); + } + } + + [HarmonyPatch(nameof(ItemAction.StopHolding)), MethodTargetPostfix] + private void Postfix_StopHolding(ItemActionData _data) + { + EntityPlayerLocal player = _data.invData.holdingEntity as EntityPlayerLocal; + if (player != null && notification != null) + { + player.Stats.NotificationRemoved(notification); + } + } +} diff --git a/Scripts/Items/Modular/ActionModuleDynamicGraze.cs b/Scripts/Items/Modular/ActionModuleDynamicGraze.cs new file mode 100644 index 0000000..2610c1e --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleDynamicGraze.cs @@ -0,0 +1,67 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; + +[TypeTarget(typeof(ItemActionDynamic))] +public class ActionModuleDynamicGraze +{ + private string dynamicSoundStart = null; + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPrefix] + private bool Prefix_ExecuteAction(ItemActionDynamic __instance, ItemActionData _actionData, bool _bReleased, out (bool executed, string originalSound) __state) + { + if (!_bReleased && !string.IsNullOrEmpty(dynamicSoundStart) && _actionData.invData.holdingEntity is EntityPlayerLocal player) + { + var targets = AnimationRiggingManager.GetRigTargetsFromPlayer(player); + if (targets && !targets.Destroyed && targets.IsAnimationSet) + { + __state = (true, __instance.soundStart); + __instance.soundStart = dynamicSoundStart; + return true; + } + } + __state = (false, null); + return true; + } + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPostfix] + private void Postfix_ExecuteAction(ItemActionDynamic __instance, (bool executed, string originalSound) __state) + { + if (__state.executed) + { + __instance.soundStart = __state.originalSound; + } + } + + [HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPrefix] + private bool Prefix_OnHoldingUpdate(ItemActionDynamic __instance, ItemActionData _actionData, out (bool executed, bool useGrazeCast) __state) + { + if (_actionData.invData.holdingEntity is EntityPlayerLocal player) + { + var targets = AnimationRiggingManager.GetRigTargetsFromPlayer(player); + if (targets && !targets.Destroyed && targets.ItemCurrent) + { + __state = (true, __instance.UseGrazingHits); + __instance.UseGrazingHits = false; + return true; + } + } + __state = (false, false); + return true; + } + + [HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPostfix] + private void Postfix_OnHoldingUpdate(ItemActionDynamic __instance, (bool executed, bool useGrazeCast) __state) + { + if (__state.executed) + { + __instance.UseGrazingHits = __state.useGrazeCast; + } + } + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props) + { + _props.ParseString("DynamicSoundStart", ref dynamicSoundStart); + } +} \ No newline at end of file diff --git a/Scripts/Items/Modular/ActionModuleDynamicMuzzleFlash.cs b/Scripts/Items/Modular/ActionModuleDynamicMuzzleFlash.cs new file mode 100644 index 0000000..9ea4506 --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleDynamicMuzzleFlash.cs @@ -0,0 +1,84 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.Utilities; + +[TypeTarget(typeof(ItemActionAttack)), ActionDataTarget(typeof(DynamicMuzzleFlashData))] +public class ActionModuleDynamicMuzzleFlash +{ + private struct State + { + public bool executed; + public string particlesMuzzleFire; + public string particlesMuzzleSmoke; + public string particlesMuzzleFireFpv; + public string particlesMuzzleSmokeFpv; + } + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationsChanged(ItemActionAttack __instance, ItemActionAttackData _data, DynamicMuzzleFlashData __customData) + { + __customData.particlesMuzzleFire = _data.invData.itemValue.GetPropertyOverrideForAction("Particles_muzzle_fire", __instance.particlesMuzzleFire, __instance.ActionIndex); + __customData.particlesMuzzleFireFpv = _data.invData.itemValue.GetPropertyOverrideForAction("Particles_muzzle_fire_fpv", __instance.particlesMuzzleFireFpv, __instance.ActionIndex); + __customData.particlesMuzzleSmoke = _data.invData.itemValue.GetPropertyOverrideForAction("Particles_muzzle_smoke", __instance.particlesMuzzleSmoke, __instance.ActionIndex); + __customData.particlesMuzzleSmokeFpv = _data.invData.itemValue.GetPropertyOverrideForAction("Particles_muzzle_smoke_fpv", __instance.particlesMuzzleSmokeFpv, __instance.ActionIndex); + if (!string.IsNullOrEmpty(__customData.particlesMuzzleFire) && !ParticleEffect.IsAvailable(__customData.particlesMuzzleFire)) + { + ParticleEffect.LoadAsset(__customData.particlesMuzzleFire); + } + if (!string.IsNullOrEmpty(__customData.particlesMuzzleFireFpv) && !ParticleEffect.IsAvailable(__customData.particlesMuzzleFireFpv)) + { + ParticleEffect.LoadAsset(__customData.particlesMuzzleFireFpv); + } + if (!string.IsNullOrEmpty(__customData.particlesMuzzleSmoke) && !ParticleEffect.IsAvailable(__customData.particlesMuzzleSmoke)) + { + ParticleEffect.LoadAsset(__customData.particlesMuzzleSmoke); + } + if (!string.IsNullOrEmpty(__customData.particlesMuzzleSmokeFpv) && !ParticleEffect.IsAvailable(__customData.particlesMuzzleSmokeFpv)) + { + ParticleEffect.LoadAsset(__customData.particlesMuzzleSmokeFpv); + } + } + + [HarmonyPatch(nameof(ItemAction.ItemActionEffects)), MethodTargetPrefix] + private bool Prefix_ItemActionEffects(ItemActionAttack __instance, DynamicMuzzleFlashData __customData, out State __state) + { + __state = new State() + { + executed = true, + particlesMuzzleFire = __instance.particlesMuzzleFire, + particlesMuzzleFireFpv = __instance.particlesMuzzleFireFpv, + particlesMuzzleSmoke = __instance.particlesMuzzleSmoke, + particlesMuzzleSmokeFpv = __instance.particlesMuzzleSmokeFpv + }; + __instance.particlesMuzzleFire = __customData.particlesMuzzleFire; + __instance.particlesMuzzleFireFpv = __customData .particlesMuzzleFireFpv; + __instance.particlesMuzzleSmoke = __customData.particlesMuzzleSmoke; + __instance.particlesMuzzleSmokeFpv = __customData.particlesMuzzleSmokeFpv; + return true; + } + + [HarmonyPatch(nameof(ItemAction.ItemActionEffects)), MethodTargetPostfix] + private void Postfix_ItemActionEffects(ItemActionAttack __instance, State __state) + { + if (__state.executed) + { + __instance.particlesMuzzleFire = __state.particlesMuzzleFire; + __instance.particlesMuzzleFireFpv = __state.particlesMuzzleFireFpv; + __instance.particlesMuzzleSmoke = __state.particlesMuzzleSmoke; + __instance.particlesMuzzleSmokeFpv = __state.particlesMuzzleSmokeFpv; + } + } + + public class DynamicMuzzleFlashData + { + public string particlesMuzzleFire; + public string particlesMuzzleFireFpv; + public string particlesMuzzleSmoke; + public string particlesMuzzleSmokeFpv; + + public DynamicMuzzleFlashData(ItemInventoryData _invData, int _indexOfAction, ActionModuleDynamicMuzzleFlash _module) + { + + } + } +} diff --git a/Scripts/Items/Modular/ActionModuleDynamicSensitivity.cs b/Scripts/Items/Modular/ActionModuleDynamicSensitivity.cs new file mode 100644 index 0000000..42c7be6 --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleDynamicSensitivity.cs @@ -0,0 +1,89 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using UnityEngine; + +[TypeTarget(typeof(ItemActionZoom)), ActionDataTarget(typeof(DynamicSensitivityData))] +public class ActionModuleDynamicSensitivity +{ + [HarmonyPatch(nameof(ItemAction.AimingSet)), MethodTargetPostfix] + private void Postfix_AimingSet(ItemActionData _actionData, bool _isAiming, bool _wasAiming, DynamicSensitivityData __customData) + { + float originalSensitivity = GamePrefs.GetFloat(EnumGamePrefs.OptionsZoomSensitivity); + if (_isAiming) + { + PlayerMoveController.Instance.mouseZoomSensitivity = originalSensitivity / Mathf.Sqrt(__customData.ZoomRatio); + } + else + { + PlayerMoveController.Instance.mouseZoomSensitivity = originalSensitivity; + } + } + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationsChanged(ItemActionZoom __instance, ItemActionData _data, DynamicSensitivityData __customData) + { + if (_data is IModuleContainerFor variableZoomData) + { + __customData.variableZoomData = variableZoomData.Instance; + } + else + { + string str = __instance.Properties.GetString("ZoomRatio"); + if (string.IsNullOrEmpty(str)) + { + str = "1"; + } + __customData.ZoomRatio = StringParsers.ParseFloat(_data.invData.itemValue.GetPropertyOverride("ZoomRatio", str)); + } + + __customData.dsRangeOverride = StringParsers.ParseVector2(_data.invData.itemValue.GetPropertyOverride("DynamicSensitivityRange", "0,0")); + } + + [HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPostfix] + private void Postfix_OnHoldingUpdate(ItemActionData _actionData, DynamicSensitivityData __customData) + { + if (((ItemActionZoom.ItemActionDataZoom)_actionData).aimingValue) + { + float originalSensitivity = GamePrefs.GetFloat(EnumGamePrefs.OptionsZoomSensitivity); + if (__customData.activated) + { + PlayerMoveController.Instance.mouseZoomSensitivity = originalSensitivity / Mathf.Sqrt(__customData.ZoomRatio); + } + else + { + PlayerMoveController.Instance.mouseZoomSensitivity = originalSensitivity; + } + } + } + + public class DynamicSensitivityData + { + public ActionModuleVariableZoom.VariableZoomData variableZoomData = null; + private float zoomRatio = 1.0f; + public Vector2 dsRangeOverride = Vector2.zero; + public bool activated = false; + + public float ZoomRatio + { + get + { + if (variableZoomData != null) + { + if (dsRangeOverride.x > 0 && dsRangeOverride.y >= dsRangeOverride.x) + { + return Mathf.Lerp(dsRangeOverride.x, dsRangeOverride.y, Mathf.InverseLerp(variableZoomData.minScale, variableZoomData.maxScale, variableZoomData.curScale)); + } + return variableZoomData.curScale; + } + return zoomRatio; + } + set => zoomRatio = value; + } + + public DynamicSensitivityData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleDynamicSensitivity _module) + { + + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Modular/ActionModuleErgoAffected.cs b/Scripts/Items/Modular/ActionModuleErgoAffected.cs new file mode 100644 index 0000000..c302f23 --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleErgoAffected.cs @@ -0,0 +1,153 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System.Collections.Generic; +using System.Reflection.Emit; +using UniLinq; +using UnityEngine; + +[TypeTarget(typeof(ItemActionZoom)), ActionDataTarget(typeof(ErgoData))] +public class ActionModuleErgoAffected +{ + public static readonly int AimSpeedModifierHash = Animator.StringToHash("AimSpeedModifier"); + public float zoomInTimeBase; + public float aimSpeedModifierBase; + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationChanged(ItemActionData _data, ItemActionZoom __instance, ErgoData __customData) + { + zoomInTimeBase = 0.3f; + __instance.Properties.ParseFloat("ZoomInTimeBase", ref zoomInTimeBase); + aimSpeedModifierBase = 1f; + __instance.Properties.ParseFloat("AimSpeedModifierBase", ref aimSpeedModifierBase); + __customData.aimStartTime = float.MaxValue; + __customData.aimSet = false; + } + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPostfix] + private void Postfix_ExecuteAction(ItemActionData _actionData, ItemActionZoom __instance, bool _bReleased, ErgoData __customData) + { + EntityAlive holdingEntity = _actionData.invData.holdingEntity; + ItemActionData prevActionData = holdingEntity.MinEventContext.ItemActionData; + holdingEntity.MinEventContext.ItemActionData = _actionData.invData.actionData[MultiActionManager.GetActionIndexForEntity(holdingEntity)]; + float ergoValue = EffectManager.GetValue(CustomEnums.WeaponErgonomics, _actionData.invData.itemValue, 0, holdingEntity); + float aimSpeedModifier = Mathf.Lerp(0.2f, 1, ergoValue); + Log.Out($"Ergo is {ergoValue}, base aim modifier is {aimSpeedModifierBase}, aim speed is {aimSpeedModifier * aimSpeedModifierBase}"); + holdingEntity.emodel.avatarController.UpdateFloat(AimSpeedModifierHash, aimSpeedModifier * aimSpeedModifierBase, true); + holdingEntity.MinEventContext.ItemActionData = prevActionData; + if ((_actionData as ItemActionZoom.ItemActionDataZoom).aimingValue && !_bReleased) + { + __customData.aimStartTime = Time.time; + } + else if (!(_actionData as ItemActionZoom.ItemActionDataZoom).aimingValue) + { + __customData.aimStartTime = float.MaxValue; + } + __customData.aimSet = false; + } + + //[MethodTargetPostfix(nameof(ItemAction.OnHoldingUpdate))] + //private void Postfix_OnHoldingUpdate(ItemActionData _actionData, ErgoData __customData) + //{ + // if ((_actionData as ItemActionZoom.ItemActionDataZoom).aimingValue && Time.time - __customData.aimStartTime > zoomInTimeBase) + // { + // __customData.aimSet = true; + // } + // else + // { + // __customData.aimSet = false; + // } + //} + + public class ErgoData + { + public float aimStartTime; + public bool aimSet; + public ActionModuleErgoAffected module; + public ErgoData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleErgoAffected _module) + { + aimStartTime = float.MaxValue; + aimSet = false; + module = _module; + } + } +} + +[HarmonyPatch] +public static class ErgoPatches +{ + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.updateAccuracy))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ItemActionRanged_updateAccuracy(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + var mtd_lerp = AccessTools.Method(typeof(Mathf), nameof(Mathf.Lerp), new[] { typeof(float), typeof(float), typeof(float) }); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_lerp)) + { + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Ldarg_2), + CodeInstruction.Call(typeof(ErgoPatches), nameof(CalcErgoModifier)), + }); + break; + } + } + + return codes; + } + + private static float CalcErgoModifier(float originalValue, ItemAction action, ItemActionData actionData, bool aiming) + { + ItemActionRanged.ItemActionDataRanged rangedData = actionData as ItemActionRanged.ItemActionDataRanged; + if (aiming && rangedData.invData.actionData[1] is IModuleContainerFor dataModule && !dataModule.Instance.aimSet && Time.time - dataModule.Instance.aimStartTime > 0) + { + ActionModuleErgoAffected.ErgoData ergoData = dataModule.Instance; + float baseAimTime = ergoData.module.zoomInTimeBase; + float baseAimMultiplier = ergoData.module.aimSpeedModifierBase; + baseAimTime /= baseAimMultiplier; + float modifiedErgo = EffectManager.GetValue(CustomEnums.WeaponErgonomics, rangedData.invData.itemValue, 1f, rangedData.invData.holdingEntity); + modifiedErgo = Mathf.Lerp(0.2f, 1, modifiedErgo); + float perc = (Time.time - ergoData.aimStartTime) * modifiedErgo / baseAimTime; + if (perc >= 1) + { + ergoData.aimSet = true; + perc = 1; + } + //Log.Out($"Time passed {Time.time - dataModule.Instance.aimStartTime} base time {baseAimTime} perc {perc}"); + return perc; + } + return originalValue; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.onHoldingEntityFired))] + [HarmonyPrefix] + private static bool Prefix_onHoldingEntityFired_ItemActionRanged(ItemActionData _actionData, out float __state) + { + __state = (_actionData as ItemActionRanged.ItemActionDataRanged).lastAccuracy; + return true; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.onHoldingEntityFired))] + [HarmonyPostfix] + private static void Postfix_onHoldingEntityFired_ItemActionRanged(ItemActionData _actionData, float __state) + { + ItemActionRanged.ItemActionDataRanged rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + if (rangedData.invData.holdingEntity.AimingGun && rangedData.invData.actionData[1] is IModuleContainerFor dataModule) + { + float aimMultiplier = EffectManager.GetValue(PassiveEffects.SpreadMultiplierAiming, rangedData.invData.itemValue, .1f, rangedData.invData.holdingEntity); + rangedData.lastAccuracy = Mathf.Lerp(__state, rangedData.lastAccuracy, aimMultiplier); + ActionModuleErgoAffected.ErgoData ergoData = dataModule.Instance; + if (Time.time > ergoData.aimStartTime) + { + ergoData.aimSet = false; + ergoData.aimStartTime = Time.time; + } + } + } +} diff --git a/Scripts/Items/Modular/ActionModuleFireModeSelector.cs b/Scripts/Items/Modular/ActionModuleFireModeSelector.cs new file mode 100644 index 0000000..8c63d86 --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleFireModeSelector.cs @@ -0,0 +1,335 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +[TypeTarget(typeof(ItemActionRanged)), ActionDataTarget(typeof(FireModeData))] +public class ActionModuleFireModeSelector +{ + public struct FireMode + { + public byte burstCount; + public bool isFullAuto; + } + public string fireModeSwitchingSound = null; + private List modeCache = new List(); + private List nameCache = new List(); + public static string[] FireModeNames = new[] + { + "FireMode", + "FireMode1", + "FireMode2", + "FireMode3", + "FireMode4", + }; + public static int[] FireModeParamHashes = new[] + { + Animator.StringToHash("FireMode"), + Animator.StringToHash("FireMode1"), + Animator.StringToHash("FireMode2"), + Animator.StringToHash("FireMode3"), + Animator.StringToHash("FireMode4"), + }; + public static int[] FireModeSwitchParamHashes = new[] + { + Animator.StringToHash("FireModeChanged"), + Animator.StringToHash("FireModeChanged1"), + Animator.StringToHash("FireModeChanged2"), + Animator.StringToHash("FireModeChanged3"), + Animator.StringToHash("FireModeChanged4"), + }; + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationChanged(ItemActionData _data, FireModeData __customData, ItemActionRanged __instance) + { + __instance.Properties.ParseString("FireModeSwitchingSound", ref fireModeSwitchingSound); + int actionIndex = _data.indexInEntityOfAction; + for (int i = 0; i < 99; i++) + { + if (!__instance.Properties.Contains($"FireMode{i}.BurstCount")) + { + break; + } + string burstCount = 1.ToString(); + __instance.Properties.ParseString($"FireMode{i}.BurstCount", ref burstCount); + string isFullAuto = false.ToString(); + __instance.Properties.ParseString($"FireMode{i}.IsFullAuto", ref isFullAuto); + string modeName = null; + __instance.Properties.ParseString($"FireMode{i}.ModeName", ref modeName); + modeCache.Add(new FireMode + { + burstCount = byte.Parse(_data.invData.itemValue.GetPropertyOverrideForAction($"FireMode{i}.BurstCount", burstCount, actionIndex)), + isFullAuto = bool.Parse(_data.invData.itemValue.GetPropertyOverrideForAction($"FireMode{i}.IsFullAuto", isFullAuto, actionIndex)) + }); + nameCache.Add(_data.invData.itemValue.GetPropertyOverrideForAction($"FireMode{i}.ModeName", modeName, actionIndex)); + } + for (int i = 0; i < 99; i++) + { + string burstCount = _data.invData.itemValue.GetPropertyOverrideForAction($"FireModePlus{i}.BurstCount", null, actionIndex); + if (burstCount == null) + { + break; + } + modeCache.Add(new FireMode + { + burstCount = byte.Parse(_data.invData.itemValue.GetPropertyOverrideForAction($"FireModePlus{i}.BurstCount", burstCount, actionIndex)), + isFullAuto = bool.Parse(_data.invData.itemValue.GetPropertyOverrideForAction($"FireModePlus{i}.IsFullAuto", "false", actionIndex)) + }); + nameCache.Add(_data.invData.itemValue.GetPropertyOverrideForAction($"FireModePlus{i}.ModeName", null, actionIndex)); + } + __customData.fireModes = modeCache.ToArray(); + modeCache.Clear(); + __customData.modeNames = nameCache.ToArray(); + nameCache.Clear(); + if (_data.invData.itemValue.GetMetadata(FireModeNames[actionIndex]) is int mode) + { + __customData.currentFireMode = (byte)mode; + } + if (__customData.currentFireMode < 0 || __customData.currentFireMode >= __customData.fireModes.Length) + { + __customData.currentFireMode = 0; + } + if (__customData.delayFiringCo != null) + { + ThreadManager.StopCoroutine(__customData.delayFiringCo); + __customData.delayFiringCo = null; + } + __customData.isRequestedByCoroutine = false; + } + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPostfix] + private void Postfix_StartHolding(ItemActionData _data, FireModeData __customData) + { + __customData.SetFireMode(_data, __customData.currentFireMode); + } + + [HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPostfix] + private static void Postfix_OnHoldingUpdate(ItemActionData _actionData, FireModeData __customData) + { + __customData.UpdateDelay(_actionData); + __customData.inputReleased = true; + } + + [HarmonyPatch(nameof(ItemAction.StopHolding)), MethodTargetPostfix] + private static void Postfix_StopHolding(FireModeData __customData) + { + if (__customData.delayFiringCo != null) + { + ThreadManager.StopCoroutine(__customData.delayFiringCo); + __customData.delayFiringCo = null; + } + __customData.isRequestedByCoroutine = false; + __customData.inputReleased = true; + } + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPrefix] + private bool Prefix_ExecuteAction(ItemActionData _actionData, ItemActionRanged __instance, FireModeData __customData, bool _bReleased) + { + if (__customData.isRequestedByCoroutine) + { + return true; + } + __customData.inputReleased = _bReleased; + if (__customData.delayFiringCo == null) + { + if (_bReleased || _actionData.invData.itemValue.Meta == 0 || _actionData.invData.itemValue.PercentUsesLeft <= 0) + { + return true; + } + FireMode curFireMode = __customData.fireModes[__customData.currentFireMode]; + if (curFireMode.burstCount == 1) + { + return true; + } + var rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + if (__instance.GetBurstCount(_actionData) > rangedData.curBurstCount) + { + __customData.StartFiring(__instance, _actionData); + } + } + return false; + } + + [HarmonyPatch(nameof(ItemActionRanged.GetBurstCount)), MethodTargetPostfix] + private void Postfix_GetBurstCount(FireModeData __customData, ref int __result) + { + FireMode fireMode = __customData.fireModes[__customData.currentFireMode]; + __result = fireMode.isFullAuto ? 999 : fireMode.burstCount; + } + + [HarmonyPatch(nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning(FireModeData __customData, ref bool __result) + { + __result |= __customData.delayFiringCo != null; + } + + public class FireModeData + { + public string switchSound; + public FireMode[] fireModes; + public string[] modeNames; + public byte currentFireMode; + public Coroutine delayFiringCo; + public bool isRequestedByCoroutine; + public float shotDelay; + public float burstDelay; + public bool inputReleased; + + public FireModeData(ItemInventoryData invData, int actionIndex, ActionModuleFireModeSelector module) + { + + } + + public void CycleFireMode(ItemActionData _data) + { + SetFireMode(_data, (byte)((currentFireMode + 1) % fireModes.Length)); + } + + public void SetFireMode(ItemActionData _data, byte _fireMode) + { + if (currentFireMode != _fireMode) + { + currentFireMode = _fireMode; + FireMode curFireMode = fireModes[currentFireMode]; + if (!string.IsNullOrEmpty(switchSound)) + { + _data.invData.holdingEntity.PlayOneShot(switchSound); + } + _data.invData.holdingEntity.emodel.avatarController.TriggerEvent(FireModeSwitchParamHashes[_data.indexInEntityOfAction]); + } + if (!string.IsNullOrEmpty(modeNames[_fireMode])) + { + GameManager.ShowTooltip(_data.invData.holdingEntity as EntityPlayerLocal, modeNames[_fireMode], true); + } + else + { + GameManager.ShowTooltip(_data.invData.holdingEntity as EntityPlayerLocal, "ttCurrentFiringMode", _fireMode.ToString(), null, null, true); + } + //GameManager.ShowTooltip(_data.invData.holdingEntity as EntityPlayerLocal, "ttCurrentFiringMode", string.IsNullOrEmpty(modeNames[_fireMode]) ? _fireMode.ToString() : Localization.Get(modeNames[_fireMode]), null, null, true); + _data.invData.holdingEntity.FireEvent(CustomEnums.onSelfBurstModeChanged); + UpdateDelay(_data); + + ItemValue itemValue = _data.invData.itemValue; + if (itemValue != null) + { + if (itemValue.Metadata == null) + { + itemValue.Metadata = new Dictionary(); + } + + if (!itemValue.Metadata.TryGetValue(ActionModuleFireModeSelector.FireModeNames[_data.indexInEntityOfAction], out var metadata) || !metadata.SetValue((int)_fireMode)) + { + itemValue.Metadata[ActionModuleFireModeSelector.FireModeNames[_data.indexInEntityOfAction]] = new TypedMetadataValue((int)_fireMode, TypedMetadataValue.TypeTag.Integer); + } + } + } + + public void UpdateDelay(ItemActionData _data) + { + FireMode curFireMode = fireModes[currentFireMode]; + if (curFireMode.burstCount == 1) + { + return; + } + float burstInterval = EffectManager.GetValue(CustomEnums.BurstShotInterval, _data.invData.itemValue, -1, _data.invData.holdingEntity); + var rangedData = _data as ItemActionRanged.ItemActionDataRanged; + if (burstInterval > 0 && rangedData.Delay > burstInterval) + { + shotDelay = burstInterval; + burstDelay = (rangedData.Delay - burstInterval) * curFireMode.burstCount; + } + else + { + shotDelay = rangedData.Delay; + burstDelay = 0; + } + } + + public void StartFiring(ItemActionRanged _instance, ItemActionData _data) + { + UpdateDelay(_data); + if (delayFiringCo != null) + { + ThreadManager.StopCoroutine(delayFiringCo); + } + ((ItemActionRanged.ItemActionDataRanged)_data).bPressed = true; + ((ItemActionRanged.ItemActionDataRanged)_data).bReleased = false; + + delayFiringCo = ThreadManager.StartCoroutine(DelayFiring(_instance, _data)); + } + + private IEnumerator DelayFiring(ItemActionRanged _instance, ItemActionData _data) + { + FireMode curFireMode = fireModes[currentFireMode]; + var rangedData = _data as ItemActionRanged.ItemActionDataRanged; + byte curBurstCount = rangedData.curBurstCount; + for (int i = 0; i < curFireMode.burstCount; i++) + { + isRequestedByCoroutine = true; + rangedData.bPressed = true; + rangedData.bReleased = false; + rangedData.m_LastShotTime = 0; + _instance.ExecuteAction(_data, false); + rangedData.curBurstCount = (byte)(curBurstCount + i + 1); + isRequestedByCoroutine = false; + if (rangedData.invData.itemValue.Meta <= 0 && !_instance.HasInfiniteAmmo(_data)) + { + goto cleanup; + } + yield return new WaitForSeconds(shotDelay); + } + yield return new WaitForSeconds(burstDelay); + + cleanup: + delayFiringCo = null; + if (inputReleased) + { + _instance.ExecuteAction(_data, true); + } + } + } +} + +[HarmonyPatch] +public static class FireModePatches +{ + [HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))] + [HarmonyPrefix] + private static bool Prefix_Update_PlayerMoveController(PlayerMoveController __instance) + { + if (DroneManager.Debug_LocalControl || !__instance.gameManager.gameStateManager.IsGameStarted() || GameStats.GetInt(EnumGameStats.GameState) != 1) + return true; + + bool isUIOpen = __instance.windowManager.IsCursorWindowOpen() || __instance.windowManager.IsInputActive() || __instance.windowManager.IsModalWindowOpen(); + + UpdateLocalInput(__instance.entityPlayerLocal, __instance.playerInput, isUIOpen, Time.deltaTime); + + return true; + } + + private static void UpdateLocalInput(EntityPlayerLocal _player, PlayerActionsLocal _input, bool _isUIOpen, float _deltaTime) + { + if (_isUIOpen || _player.emodel.IsRagdollActive || _player.IsDead() || _player.AttachedToEntity != null) + { + return; + } + + if (PlayerActionToggleFireMode.Instance.Enabled && PlayerActionToggleFireMode.Instance.Toggle.WasPressed) + { + if (_player.inventory.IsHoldingItemActionRunning()) + { + return; + } + + var actionData = _player.inventory.holdingItemData.actionData[MultiActionManager.GetActionIndexForEntity(_player)]; + if (actionData is IModuleContainerFor fireModeData) + { + fireModeData.Instance.CycleFireMode(actionData); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Modular/ActionModuleHoldOpen.cs b/Scripts/Items/Modular/ActionModuleHoldOpen.cs new file mode 100644 index 0000000..75a1c46 --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleHoldOpen.cs @@ -0,0 +1,85 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using System.Collections; +using UnityEngine; + +[TypeTarget(typeof(ItemActionRanged))] +public class ActionModuleHoldOpen +{ + private const string emptyAnimatorBool = "empty"; + private int emptyAnimatorBoolHash; + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props, ItemActionRanged __instance) + { + int metaIndex = __instance.ActionIndex; + if (_props.Values.TryGetValue("ShareMetaWith", out string str) && int.TryParse(str, out metaIndex)) + { + + } + if (metaIndex > 0) + { + emptyAnimatorBoolHash = Animator.StringToHash(emptyAnimatorBool + __instance.ActionIndex); + } + else + { + emptyAnimatorBoolHash = Animator.StringToHash(emptyAnimatorBool); + } + } + + [HarmonyPatch(nameof(ItemActionRanged.getUserData)), MethodTargetPostfix] + public void Postfix_getUserData(ItemActionData _actionData, ref int __result) + { + __result |= (_actionData.invData.itemValue.Meta <= 0 ? 1 : 0); + } + + [HarmonyPatch(nameof(ItemAction.ItemActionEffects)), MethodTargetPostfix] + public void Postfix_ItemActionEffects(ItemActionData _actionData, int _firingState, int _userData) + { + if (_firingState != (int)ItemActionFiringState.Off && (_userData & 1) > 0) + _actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(emptyAnimatorBoolHash, true, false); + } + + [HarmonyPatch(nameof(ItemActionRanged.ReloadGun)), MethodTargetPostfix] + public void Postfix_ReloadGun(ItemActionData _actionData) + { + //delay 2 frames before reloading, since the animation is likely to be triggered the next frame this is called + ThreadManager.StartCoroutine(DelaySetEmpty(_actionData, false, 2)); + } + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPrefix] + public bool Prefix_StartHolding(ItemActionData _data) + { + //delay 1 frame before equipping weapon + if (_data.invData.itemValue.Meta <= 0) + ThreadManager.StartCoroutine(DelaySetEmpty(_data, true, 2)); + return true; + } + + [HarmonyPatch(nameof(ItemActionRanged.ConsumeAmmo)), MethodTargetPostfix] + public void Postfix_ConsumeAmmo(ItemActionData _actionData) + { + if (_actionData.invData.itemValue.Meta == 0) + _actionData.invData.holdingEntity.FireEvent(CustomEnums.onSelfMagzineDeplete, true); + } + + [HarmonyPatch(nameof(ItemAction.SwapAmmoType)), MethodTargetPrefix] + public bool Prefix_SwapAmmoType(EntityAlive _entity) + { + _entity.emodel.avatarController.UpdateBool(emptyAnimatorBoolHash, true, false); + return true; + } + + private IEnumerator DelaySetEmpty(ItemActionData _actionData, bool empty, int delay) + { + for (int i = 0; i < delay; i++) + { + yield return null; + } + if (_actionData.invData.holdingEntity.inventory.holdingItemIdx == _actionData.invData.slotIdx) + { + _actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(emptyAnimatorBoolHash, empty, false); + } + yield break; + } +} \ No newline at end of file diff --git a/Scripts/Items/Modular/ActionModuleInspectable.cs b/Scripts/Items/Modular/ActionModuleInspectable.cs new file mode 100644 index 0000000..b11d2d0 --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleInspectable.cs @@ -0,0 +1,24 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; + +[TypeTarget(typeof(ItemAction))] +public class ActionModuleInspectable +{ + public bool allowEmptyInspect; + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props) + { + allowEmptyInspect = _props.GetBool("allowEmptyInspect"); + } + + [HarmonyPatch(typeof(ItemActionDynamic), nameof(ItemAction.CancelAction)), MethodTargetPostfix] + private void Postfix_CancelAction_ItemActionDynamic(ItemActionDynamic.ItemActionDynamicData _actionData) + { + var entity = _actionData.invData.holdingEntity; + if (!entity.MovementRunning && _actionData != null && !entity.inventory.holdingItem.IsActionRunning(entity.inventory.holdingItemData)) + { + entity.emodel.avatarController._setTrigger("weaponInspect", false); + } + } +} diff --git a/Scripts/Items/Modular/ActionModuleInterruptReload.cs b/Scripts/Items/Modular/ActionModuleInterruptReload.cs new file mode 100644 index 0000000..fd836fe --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleInterruptReload.cs @@ -0,0 +1,225 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using UnityEngine; + +[TypeTarget(typeof(ItemActionRanged)), ActionDataTarget(typeof(InterruptData))] +public class ActionModuleInterruptReload +{ + public float holdBeforeCancel = 0.06f; + public string firingStateName = ""; + public bool instantFiringCancel = false; + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPrefix] + private bool Prefix_StartHolding(InterruptData __customData) + { + __customData.Reset(); + return true; + } + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props) + { + firingStateName = _props.GetString("FiringStateFullName"); + instantFiringCancel = _props.GetBool("InstantFiringCancel"); + } + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationsChanged(ItemActionData _data, InterruptData __customData) + { + var invData = _data.invData; + __customData.itemAnimator = AnimationGraphBuilder.DummyWrapper; + __customData.eventBridge = null; + if (invData.model && invData.model.TryGetComponent(out var targets) && !targets.Destroyed && targets.IsAnimationSet) + { + __customData.itemAnimator = targets.GraphBuilder.WeaponWrapper; + if (__customData.itemAnimator.IsValid) + { + __customData.eventBridge = targets.ItemAnimator.GetComponent(); + } + } + } + + private struct State + { + public bool executed; + public bool isReloading; + public bool isWeaponReloading; + public float lastShotTime; + } + + [HarmonyPatch(nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning(ref bool __result, InterruptData __customData) + { + __result &= !__customData.instantFiringRequested; + } + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPrefix] + private bool Prefix_ExecuteAction(ItemActionData _actionData, bool _bReleased, InterruptData __customData, out State __state) + { + __state = default; + if (!_bReleased && __customData.isInterruptRequested && __customData.instantFiringRequested) + { + if (_actionData.invData.itemValue.Meta > 0) + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"instant firing cancel prefix!"); + ItemActionRanged.ItemActionDataRanged rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + __state.executed = true; + __state.isReloading = rangedData.isReloading; + __state.isWeaponReloading = rangedData.isWeaponReloading; + __state.lastShotTime = rangedData.m_LastShotTime; + rangedData.isReloading = false; + rangedData.isWeaponReloading = false; + } + else + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"not fired! meta is 0"); + __customData.isInterruptRequested = false; + __customData.instantFiringRequested = false; + return false; + } + } + return true; + } + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPostfix] + private void Postfix_ExecuteAction(ItemActionData _actionData, InterruptData __customData, State __state) + { + if (__state.executed) + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"instant firing cancel postfix!"); + ItemActionRanged.ItemActionDataRanged rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + rangedData.isReloading = __state.isReloading; + rangedData.isWeaponReloading = __state.isWeaponReloading; + if (__customData.itemAnimator.IsValid && __customData.eventBridge) + { + if (rangedData.m_LastShotTime > __state.lastShotTime && rangedData.m_LastShotTime < Time.time + 1f) + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"executed!"); + __customData.eventBridge.OnReloadEnd(); + __customData.itemAnimator.Play(firingStateName, -1, 0f); + } + else + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"not fired! last shot time {__state.lastShotTime} ranged data shot time {rangedData.m_LastShotTime} cur time {Time.time}"); + __customData.isInterruptRequested = false; + __customData.instantFiringRequested = false; + } + } + } + } + + [HarmonyPatch(nameof(ItemAction.ItemActionEffects)), MethodTargetPrefix] + private bool Prefix_ItemActionEffects(ItemActionData _actionData, int _firingState, InterruptData __customData) + { + var rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + if (_firingState != 0 && (rangedData.isReloading || rangedData.isWeaponReloading) && !(rangedData.invData.holdingEntity is EntityPlayerLocal) && __customData.eventBridge) + { + __customData.eventBridge.OnReloadEnd(); + __customData.itemAnimator.Play(firingStateName, -1, 0f); + } + return true; + } + + public bool IsRequestPossible(InterruptData interruptData) + { + return interruptData.eventBridge && interruptData.itemAnimator.IsValid; + } + + public class InterruptData + { + public bool isInterruptRequested; + public float holdStartTime = -1f; + public bool instantFiringRequested = false; + public AnimationReloadEvents eventBridge; + public IAnimatorWrapper itemAnimator; + + public InterruptData(ItemInventoryData invData, int actionIndex, ActionModuleInterruptReload module) + { + //if (invData.model && invData.model.TryGetComponent(out var targets) && !targets.Destroyed) + //{ + // itemAnimator = targets.ItemAnimator; + // if (itemAnimator) + // { + // eventBridge = itemAnimator.GetComponent(); + // } + //} + } + + public void Reset() + { + isInterruptRequested = false; + holdStartTime = -1f; + instantFiringRequested = false; + } + } +} + +[HarmonyPatch] +internal static class ReloadInterruptionPatches +{ + //interrupt reload with firing + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.ExecuteAction))] + [HarmonyPrefix] + private static bool Prefix_ExecuteAction_ItemClass(ItemClass __instance, int _actionIdx, ItemInventoryData _data, bool _bReleased, PlayerActionsLocal _playerActions) + { + ItemAction curAction = __instance.Actions[_actionIdx]; + if (curAction is ItemActionRanged || curAction is ItemActionZoom) + { + int curActionIndex = MultiActionManager.GetActionIndexForEntity(_data.holdingEntity); + var rangedAction = __instance.Actions[curActionIndex] as ItemActionRanged; + var rangedData = _data.actionData[curActionIndex] as ItemActionRanged.ItemActionDataRanged; + if (rangedData != null && rangedData is IModuleContainerFor dataModule && rangedAction is IModuleContainerFor actionModule) + { + if (!_bReleased && _playerActions != null && actionModule.Instance.IsRequestPossible(dataModule.Instance) && ((_playerActions.Primary.IsPressed && _actionIdx == curActionIndex && _data.itemValue.Meta > 0) || (_playerActions.Secondary.IsPressed && curAction is ItemActionZoom)) && (rangedData.isReloading || rangedData.isWeaponReloading) && !dataModule.Instance.isInterruptRequested) + { + if (dataModule.Instance.holdStartTime < 0) + { + dataModule.Instance.holdStartTime = Time.time; + return false; + } + if (Time.time - dataModule.Instance.holdStartTime >= actionModule.Instance.holdBeforeCancel) + { + if (!rangedAction.reloadCancelled(rangedData)) + { + rangedAction.CancelReload(rangedData); + } + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"interrupt requested!"); + dataModule.Instance.isInterruptRequested = true; + if (actionModule.Instance.instantFiringCancel && curAction is ItemActionRanged) + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"instant firing cancel!"); + dataModule.Instance.instantFiringRequested = true; + return true; + } + } + return false; + } + if (_bReleased) + { + dataModule.Instance.Reset(); + } + } + } + return true; + } + + [HarmonyPatch(typeof(ItemAction), nameof(ItemAction.CancelReload))] + [HarmonyPrefix] + private static bool Prefix_CancelReload_ItemAction(ItemActionData _actionData) + { + if (_actionData?.invData?.holdingEntity is EntityPlayerLocal && AnimationRiggingManager.IsHoldingRiggedWeapon(_actionData.invData.holdingEntity as EntityPlayerLocal)) + { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/Scripts/Items/Modular/ActionModuleInvariableRPM.cs b/Scripts/Items/Modular/ActionModuleInvariableRPM.cs new file mode 100644 index 0000000..0dbf9f8 --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleInvariableRPM.cs @@ -0,0 +1,60 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System.Collections.Generic; +using System.Reflection.Emit; +using UniLinq; + +[TypeTarget(typeof(ItemActionRanged))] +public class ActionModuleInvariableRPM +{ + //added as a transpiler so that it's applied before all post processing + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.OnHoldingUpdate)), MethodTargetTranspiler] + private static IEnumerable Transpiler_OnHoldingUpdate_ItemActionRanged(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_getvalue)) + { + int start = -1; + for (int j = i; j >= 0; j--) + { + if (codes[j].opcode == OpCodes.Stloc_0) + { + start = j + 2; + break; + } + } + if (start >= 0) + { + codes.InsertRange(i + 2, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.Call(typeof(ActionModuleInvariableRPM), nameof(CalcFixedRPM)) + }); + codes.RemoveRange(start, i - start + 2); + //Log.Out("Invariable RPM Patch applied!"); + } + break; + } + } + + return codes; + } + + private static float CalcFixedRPM(ItemActionRanged rangedAction, ItemActionRanged.ItemActionDataRanged rangedData) + { + float rpm = 60f / rangedData.OriginalDelay; + float perc = 1f; + var tags = rangedData.invData.item.ItemTags; + MultiActionManager.ModifyItemTags(rangedData.invData.itemValue, rangedData, ref tags); + rangedData.invData.item.Effects.ModifyValue(rangedData.invData.holdingEntity, PassiveEffects.RoundsPerMinute, ref rpm, ref perc, rangedData.invData.itemValue.Quality, tags); + //Log.Out($"fixed RPM {res}"); + return 60f / (rpm * perc); + } +} \ No newline at end of file diff --git a/Scripts/Items/Modular/ActionModuleLocalPassiveCache.cs b/Scripts/Items/Modular/ActionModuleLocalPassiveCache.cs new file mode 100644 index 0000000..8c5ec9e --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleLocalPassiveCache.cs @@ -0,0 +1,105 @@ +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System; +using System.Collections; +using System.Collections.Generic; + +[TypeTarget(typeof(ItemAction)), ActionDataTarget(typeof(LocalPassiveCacheData))] +public class ActionModuleLocalPassiveCache +{ + //public int[] nameHashes; + + //[MethodTargetPostfix(nameof(ItemAction.ReadFrom))] + //private void Postfix_ReadFrom(DynamicProperties _props) + //{ + // string str = _props.Values["CachePassives"]; + // if (!string.IsNullOrEmpty(str)) + // { + // nameHashes = Array.ConvertAll(str.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), s => s.GetHashCode()); + // } + //} + + //[MethodTargetPrefix(nameof(ItemAction.StartHolding))] + //private bool Prefix_StartHolding(ItemActionData _data, LocalPassiveCacheData __customData) + //{ + // if (nameHashes != null) + // { + // for (int i = 0; i < nameHashes.Length; i++) + // { + // __customData.passives[i] = EffectManager.GetValue(nameHashes[i], _data.invData.itemValue, 0, _data.invData.holdingEntity); + // __customData.markedForCache[i] = false; + // } + // } + // return true; + //} + + //[MethodTargetPrefix(nameof(ItemAction.OnHoldingUpdate))] + //private bool Prefix_OnHoldingUpdate(ItemActionData _actionData, LocalPassiveCacheData __customData) + //{ + // if (!_actionData.invData.holdingEntity.isEntityRemote && nameHashes != null) + // { + // for (int i = 0; i < nameHashes.Length; i++) + // { + // if (__customData.markedForCache[i]) + // { + // __customData.cache[i] = EffectManager.GetValue(nameHashes[i], _actionData.invData.itemValue, 0, _actionData.invData.holdingEntity); + // __customData.markedForCache[i] = false; + // } + // } + // } + + // return true; + //} + + public class LocalPassiveCacheData : IEnumerable + { + //public float[] cache; + //public bool[] markedForCache; + //public ActionModuleLocalPassiveCache _cacheModule; + public ItemInventoryData invData; + private Dictionary dict_hash_value = new Dictionary(); + private Dictionary dict_hash_name = new Dictionary(); + + public LocalPassiveCacheData(ItemInventoryData _invData, int _indexOfAction, ActionModuleLocalPassiveCache _cacheModule) + { + //this._cacheModule = _cacheModule; + this.invData = _invData; + //if (_cacheModule.nameHashes != null) + //{ + // cache = new float[_cacheModule.nameHashes.Length]; + // //markedForCache = new bool[_cacheModule.nameHashes.Length]; + //} + } + + public void CachePassive(PassiveEffects target, int targetHash, string targetStr, FastTags tags) + { + if (invData.holdingEntity.isEntityRemote) + return; + if (!dict_hash_name.ContainsKey(targetHash)) + dict_hash_name[targetHash] = targetStr; + + dict_hash_value[targetHash] = EffectManager.GetValue(target, invData.itemValue, 0, invData.holdingEntity, null, tags); + //markedForCache[index] = true; + } + + public float GetCachedValue(int targetHash) + { + return dict_hash_value.TryGetValue(targetHash, out float res) ? res : 0; + } + + public string GetCachedName(int targetHash) + { + return dict_hash_name.TryGetValue(targetHash, out string res) ? res : string.Empty; + } + + public IEnumerator GetEnumerator() + { + return dict_hash_value.Keys.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/Scripts/Items/Modular/ActionModuleMetaConsumer.cs b/Scripts/Items/Modular/ActionModuleMetaConsumer.cs new file mode 100644 index 0000000..d656fef --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleMetaConsumer.cs @@ -0,0 +1,178 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using System; +using System.Collections.Generic; +using System.Reflection.Emit; +using UniLinq; + +[TypeTarget(typeof(ItemActionRanged))] +public class ActionModuleMetaConsumer +{ + public string[] consumeDatas; + public FastTags[] consumeTags; + private float[] consumeStocks; + private float[] consumeValues; + private static FastTags TagsConsumption = FastTags.Parse("ConsumptionValue"); + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props, ItemAction __instance) + { + string consumeData = string.Empty; + _props.Values.TryGetValue("ConsumeData", out consumeData); + _props.Values.TryGetValue("ConsumeTags", out string tags); + FastTags commonTags = string.IsNullOrEmpty(tags) ? FastTags.none : FastTags.Parse(tags); + if (string.IsNullOrEmpty(consumeData)) + { + Log.Error($"No consume data found on item {__instance.item.Name} action {__instance.ActionIndex}"); + return; + } + + consumeDatas = consumeData.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray(); + consumeTags = consumeDatas.Select(s => FastTags.Parse(s) | commonTags | TagsConsumption).ToArray(); + consumeStocks = new float[consumeDatas.Length]; + consumeValues = new float[consumeDatas.Length]; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.ExecuteAction)), MethodTargetTranspiler] + private static IEnumerable Transpiler_ItemActionRanged_ExecuteAction(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + var fld_started = AccessTools.Field(typeof(ItemActionRanged.ItemActionDataRanged), nameof(ItemActionRanged.ItemActionDataRanged.burstShotStarted)); + var fld_infinite = AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.InfiniteAmmo)); + var mtd_consume = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.ConsumeAmmo)); + var lbd_module = generator.DeclareLocal(typeof(ActionModuleMetaConsumer)); + var prop_instance = AccessTools.PropertyGetter(typeof(IModuleContainerFor), nameof(IModuleContainerFor.Instance)); + var prop_itemvalue = AccessTools.PropertyGetter(typeof(ItemInventoryData), nameof(ItemInventoryData.itemValue)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 6) + { + codes.InsertRange(i - 4, new[] + { + new CodeInstruction(OpCodes.Ldarg_0).WithLabels(codes[i - 4].ExtractLabels()), + new CodeInstruction(OpCodes.Castclass, typeof(IModuleContainerFor)), + new CodeInstruction(OpCodes.Callvirt, prop_instance), + new CodeInstruction(OpCodes.Stloc_S, lbd_module), + }); + i += 4; + } + else if (codes[i].StoresField(fld_started) && codes[i - 1].LoadsConstant(1)) + { + var lbl = generator.DefineLabel(); + var original = codes[i - 2]; + codes.InsertRange(i - 2, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_module).WithLabels(original.ExtractLabels()), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)), + new CodeInstruction(OpCodes.Callvirt, prop_itemvalue), + new CodeInstruction(OpCodes.Ldloc_S, 6), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemActionAttack), nameof(ItemActionAttack.soundEmpty)), + CodeInstruction.Call(typeof(ActionModuleMetaConsumer), nameof(CheckAndCacheMetaData)), + new CodeInstruction(OpCodes.Brtrue_S, lbl), + new CodeInstruction(OpCodes.Ret) + }); + original.WithLabels(lbl); + i += 10; + } + else if (codes[i].Calls(mtd_consume)) + { + var lbl = generator.DefineLabel(); + for (int j = i - 1; j >= 0; j--) + { + if (codes[j].LoadsField(fld_infinite) && codes[j + 1].Branches(out _)) + { + codes[j + 1].operand = lbl; + break; + } + } + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_module).WithLabels(lbl), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)), + new CodeInstruction(OpCodes.Callvirt, prop_itemvalue), + new CodeInstruction(OpCodes.Ldloc_S, 6), + CodeInstruction.Call(typeof(ActionModuleMetaConsumer), nameof(ConsumeMetaData)), + }); + break; + } + } + + return codes; + } + + public bool CheckAndCacheMetaData(ItemValue itemValue, EntityAlive holdingEntity, string soundEmpty) + { + for (int i = 0; i < consumeDatas.Length; i++) + { + string consumeData = consumeDatas[i]; + float stock = (float)itemValue.GetMetadata(consumeData); + float consumption = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, float.MaxValue, holdingEntity, null, consumeTags[i]); + if (stock < consumption) + { + holdingEntity.PlayOneShot(soundEmpty); + return false; + } + consumeStocks[i] = stock; + consumeValues[i] = consumption; + } + return true; + } + + public void ConsumeMetaData(ItemValue itemValue, EntityAlive holdingEntity) + { + for (int i = 0; i < consumeDatas.Length; i++) + { + itemValue.SetMetadata(consumeDatas[i], consumeStocks[i] - consumeValues[i], TypedMetadataValue.TypeTag.Float); + holdingEntity.MinEventContext.Tags = consumeTags[i]; + holdingEntity.FireEvent(CustomEnums.onRechargeValueUpdate, true); + } + } + + //[HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPrefix] + //private bool Prefix_ExecuteAction(ItemActionData _actionData, bool _bReleased, ItemActionRanged __instance) + //{ + // ItemActionRanged.ItemActionDataRanged _data = _actionData as ItemActionRanged.ItemActionDataRanged; + // EntityAlive holdingEntity = _actionData.invData.holdingEntity; + // ItemValue itemValue = _actionData.invData.itemValue; + // if (!_bReleased) + // { + // int burstCount = __instance.GetBurstCount(_actionData); + // if (holdingEntity.inventory.holdingItemItemValue.PercentUsesLeft <= 0f || (_data.curBurstCount >= burstCount && burstCount != -1) || (!__instance.InfiniteAmmo && itemValue.Meta <= 0)) + // { + // return true; + // } + + // for (int i = 0; i < consumeDatas.Length; i++) + // { + // string consumeData = consumeDatas[i]; + // float stock = (float)itemValue.GetMetadata(consumeData); + // float consumption = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, float.MaxValue, _actionData.invData.holdingEntity, null, consumeTags[i]); + // if (stock < consumption) + // { + // if (!_data.bPressed) + // { + // holdingEntity.PlayOneShot(__instance.soundEmpty); + // _data.bPressed = true; + // } + // return false; + // } + // consumeStocks[i] = stock; + // consumeValues[i] = consumption; + // } + + // for (int i = 0; i < consumeDatas.Length; i++) + // { + // itemValue.SetMetadata(consumeDatas[i], consumeStocks[i] - consumeValues[i], TypedMetadataValue.TypeTag.Float); + // holdingEntity.MinEventContext.Tags = consumeTags[i]; + // holdingEntity.FireEvent(CustomEnums.onRechargeValueUpdate, true); + // } + // } + // return true; + //} +} \ No newline at end of file diff --git a/Scripts/Items/Modular/ActionModuleMetaRecharger.cs b/Scripts/Items/Modular/ActionModuleMetaRecharger.cs new file mode 100644 index 0000000..2a1894b --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleMetaRecharger.cs @@ -0,0 +1,166 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System; +using UniLinq; +using UnityEngine; + +[TypeTarget(typeof(ItemActionRanged)), ActionDataTarget(typeof(MetaRechargerData))] +public class ActionModuleMetaRecharger +{ + public struct RechargeTags + { + public FastTags tagsOriginal; + public FastTags tagsInterval; + public FastTags tagsMaximum; + public FastTags tagsValue; + public FastTags tagsDecrease; + public FastTags tagsDecreaseInterval; + } + + public string[] rechargeDatas; + public RechargeTags[] rechargeTags; + private static readonly FastTags TagsInterval = FastTags.Parse("RechargeDataInterval"); + private static readonly FastTags TagsMaximum = FastTags.Parse("RechargeDataMaximum"); + private static readonly FastTags TagsValue = FastTags.Parse("RechargeDataValue"); + private static readonly FastTags TagsDecrease = FastTags.Parse("RechargeDataDecrease"); + private static readonly FastTags TagsDecreaseInterval = FastTags.Parse("RechargeDecreaseInterval"); + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props, ItemAction __instance) + { + rechargeDatas = null; + rechargeTags = null; + string rechargeData = string.Empty; + _props.Values.TryGetValue("RechargeData", out rechargeData); + _props.Values.TryGetValue("RechargeTags", out string tags); + FastTags commonTags = string.IsNullOrEmpty(tags) ? FastTags.none : FastTags.Parse(tags); + if (string.IsNullOrEmpty(rechargeData)) + { + Log.Error($"No recharge data found on item {__instance.item.Name} action {__instance.ActionIndex}"); + return; + } + rechargeDatas = rechargeData.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray(); + rechargeTags = rechargeDatas.Select(s => + { + var _tags = FastTags.Parse(s) | commonTags; + return new RechargeTags + { + tagsOriginal = _tags, + tagsInterval = _tags | TagsInterval, + tagsMaximum = _tags | TagsMaximum, + tagsValue = _tags | TagsValue, + tagsDecrease = _tags | TagsDecrease, + tagsDecreaseInterval = _tags | TagsDecreaseInterval, + }; + }).ToArray(); + } + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPrefix] + private bool Prefix_StartHolding(ItemActionData _data, MetaRechargerData __customData) + { + EntityAlive holdingEntity = _data.invData.holdingEntity; + if (holdingEntity.isEntityRemote) + return true; + for (int i = 0; i < rechargeDatas.Length; i++) + { + holdingEntity.MinEventContext.Tags = rechargeTags[i].tagsOriginal; + holdingEntity.FireEvent(CustomEnums.onRechargeValueUpdate, true); + } + return true; + } + + public class MetaRechargerData : IBackgroundInventoryUpdater + { + private ActionModuleMetaRecharger module; + private float lastUpdateTime, lastDecreaseTime; + private int indexOfAction; + + public int Index => indexOfAction; + + public MetaRechargerData(ItemInventoryData _invData, int _indexOfAction, ActionModuleMetaRecharger _rechargeModule) + { + module = _rechargeModule; + indexOfAction = _indexOfAction; + lastUpdateTime = lastDecreaseTime = Time.time; + if (_rechargeModule.rechargeDatas == null) + return; + + BackgroundInventoryUpdateManager.RegisterUpdater(_invData.holdingEntity, _invData.slotIdx, this); + } + + public bool OnUpdate(ItemInventoryData invData) + { + ItemValue itemValue = invData.itemValue; + EntityAlive holdingEntity = invData.holdingEntity; + holdingEntity.MinEventContext.ItemInventoryData = invData; + holdingEntity.MinEventContext.ItemValue = itemValue; + holdingEntity.MinEventContext.ItemActionData = invData.actionData[indexOfAction]; + float curTime = Time.time; + bool res = false; + for (int i = 0; i < module.rechargeDatas.Length; i++) + { + string rechargeData = module.rechargeDatas[i]; + RechargeTags rechargeTag = module.rechargeTags[i]; + float updateInterval = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, float.MaxValue, holdingEntity, null, rechargeTag.tagsInterval); + float decreaseInterval = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, float.MaxValue, holdingEntity, null, rechargeTag.tagsDecreaseInterval); + float deltaTime = curTime - lastUpdateTime; + float deltaDecreaseTime = curTime - lastDecreaseTime; + if (deltaTime > updateInterval || deltaDecreaseTime > decreaseInterval) + { + //Log.Out($"last update time {lastUpdateTime} cur time {curTime} update interval {updateInterval}"); + float cur; + if (!itemValue.HasMetadata(rechargeData)) + { + itemValue.SetMetadata(rechargeData, 0, TypedMetadataValue.TypeTag.Float); + cur = 0; + } + else + { + cur = (float)itemValue.GetMetadata(rechargeData); + } + float max = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, 0, holdingEntity, null, rechargeTag.tagsMaximum); + bool modified = false; + if (cur > max) + { + if (deltaDecreaseTime > decreaseInterval) + { + //the result updated here won't exceed max so it's set somewhere else, decrease slowly + float dec = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, float.MaxValue, holdingEntity, null, rechargeTag.tagsDecrease); + cur = Mathf.Max(cur - dec, max); + lastDecreaseTime = curTime; + modified = true; + } + lastUpdateTime = curTime; + } + else + { + if (cur < max && deltaTime > updateInterval) + { + //add up and clamp to max + float add = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, 0, holdingEntity, null, rechargeTag.tagsValue); + cur = Mathf.Min(cur + add, max); + lastUpdateTime = curTime; + modified = true; + } + //always set lastDecreaseTime if not overcharged, since we don't want overcharged data to decrease right after it's charged + lastDecreaseTime = curTime; + } + + if (modified) + { + itemValue.SetMetadata(rechargeData, cur, TypedMetadataValue.TypeTag.Float); + } + if (invData.slotIdx == holdingEntity.inventory.holdingItemIdx && invData.slotIdx >= 0) + { + holdingEntity.MinEventContext.Tags = rechargeTag.tagsOriginal; + itemValue.FireEvent(CustomEnums.onRechargeValueUpdate, holdingEntity.MinEventContext); + //Log.Out($"action index is {holdingEntity.MinEventContext.ItemActionData.indexInEntityOfAction} after firing event"); + } + res |= modified; + } + } + return res; + } + } +} diff --git a/Scripts/Items/Modular/ActionModuleMultiActionFix.cs b/Scripts/Items/Modular/ActionModuleMultiActionFix.cs new file mode 100644 index 0000000..009fbfc --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleMultiActionFix.cs @@ -0,0 +1,222 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; + +[TypeTarget(typeof(ItemActionAttack)), ActionDataTarget(typeof(MultiActionData))] +public class ActionModuleMultiActionFix +{ + private int actionIndex; + public string GetDisplayType(ItemValue itemValue) + { + string displayType = itemValue.GetPropertyOverrideForAction("DisplayType", null, actionIndex); + if (string.IsNullOrEmpty(displayType)) + { + displayType = itemValue.ItemClass.DisplayType; + } + return displayType; + } + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + public void Postfix_ReadFrom(ItemActionAttack __instance) + { + actionIndex = __instance.ActionIndex; + } + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPrefix] + public bool Prefix_StartHolding(ItemActionData _data, out ItemActionData __state) + { + SetAndSaveItemActionData(_data, out __state); + return true; + } + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPostfix] + public void Postfix_StartHolding(ItemActionData _data, ItemActionData __state) + { + RestoreItemActionData(_data, __state); + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + public void Postfix_OnModificationChanged_ItemActionRanged(ItemActionData _data, ItemActionAttack __instance) + { + var rangedData = _data as ItemActionRanged.ItemActionDataRanged; + if (rangedData != null) + { + string muzzleName; + string indexExtension = (_data.indexInEntityOfAction > 0 ? _data.indexInEntityOfAction.ToString() : ""); + if (rangedData.IsDoubleBarrel) + { + muzzleName = _data.invData.itemValue.GetPropertyOverrideForAction($"Muzzle_L_Name", $"Muzzle_L{indexExtension}", _data.indexInEntityOfAction); + rangedData.muzzle = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, muzzleName) ?? rangedData.muzzle; + muzzleName = _data.invData.itemValue.GetPropertyOverrideForAction($"Muzzle_R_Name", $"Muzzle_R{indexExtension}", _data.indexInEntityOfAction); + rangedData.muzzle2 = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, muzzleName) ?? rangedData.muzzle2; + } + else + { + muzzleName = _data.invData.itemValue.GetPropertyOverrideForAction($"Muzzle_Name", $"Muzzle{indexExtension}", _data.indexInEntityOfAction); + rangedData.muzzle = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, muzzleName) ?? rangedData.muzzle; + } + } + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + public void Postfix_OnModificationChanged_ItemActionLauncher(ItemActionData _data, ItemActionAttack __instance) + { + Postfix_OnModificationChanged_ItemActionRanged(_data, __instance); + if (_data is ItemActionLauncher.ItemActionDataLauncher launcherData) + { + string indexExtension = (_data.indexInEntityOfAction > 0 ? _data.indexInEntityOfAction.ToString() : ""); + string jointName = _data.invData.itemValue.GetPropertyOverrideForAction($"ProjectileJoint_Name", $"ProjectileJoint{indexExtension}", _data.indexInEntityOfAction); + launcherData.projectileJoint = AnimationRiggingManager.GetTransformOverrideByName(launcherData.invData.model, jointName) ?? launcherData.projectileJoint; + } + } + + [HarmonyPatch(nameof(ItemAction.StopHolding)), MethodTargetPrefix] + public bool Prefix_StopHolding(ItemActionData _data, out ItemActionData __state) + { + SetAndSaveItemActionData(_data, out __state); + return true; + } + + [HarmonyPatch(nameof(ItemAction.StopHolding)), MethodTargetPostfix] + public void Postfix_StopHolding(ItemActionData _data, ItemActionData __state) + { + RestoreItemActionData(_data, __state); + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemAction.ItemActionEffects)), MethodTargetPrefix] + public bool Prefix_ItemActionEffects(ItemActionData _actionData, out ItemActionData __state) + { + SetAndSaveItemActionData(_actionData, out __state); + return true; + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemAction.ItemActionEffects)), MethodTargetPostfix] + public void Postfix_ItemActionEffects(ItemActionData _actionData, ItemActionData __state) + { + RestoreItemActionData(_actionData, __state); + } + + [HarmonyPatch(nameof(ItemAction.CancelAction)), MethodTargetPrefix] + public bool Prefix_CancelAction(ItemActionData _actionData, out ItemActionData __state) + { + SetAndSaveItemActionData(_actionData, out __state); + return true; + } + + [HarmonyPatch(nameof(ItemAction.CancelAction)), MethodTargetPostfix] + public void Postfix_CancelAction(ItemActionData _actionData, ItemActionData __state) + { + RestoreItemActionData(_actionData, __state); + } + + [HarmonyPatch(nameof(ItemActionAttack.CancelReload)), MethodTargetPrefix] + public bool Prefix_CancelReload(ItemActionData _actionData, out ItemActionData __state) + { + SetAndSaveItemActionData(_actionData, out __state); + return true; + } + + [HarmonyPatch(nameof(ItemActionAttack.CancelReload)), MethodTargetPostfix] + public void Postfix_CancelReload(ItemActionData _actionData, ItemActionData __state) + { + RestoreItemActionData(_actionData, __state); + } + + [HarmonyPatch(nameof(ItemActionAttack.ReloadGun)), MethodTargetPrefix] + public bool Prefix_ReloadGun(ItemActionData _actionData) + { + //int reloadAnimationIndex = MultiActionManager.GetMetaIndexForActionIndex(_actionData.invData.holdingEntity.entityId, _actionData.indexInEntityOfAction); + _actionData.invData.holdingEntity.emodel?.avatarController?.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, _actionData.indexInEntityOfAction, false); + _actionData.invData.holdingEntity.MinEventContext.ItemActionData = _actionData; + //MultiActionManager.GetMappingForEntity(_actionData.invData.holdingEntity.entityId)?.SaveMeta(); + return true; + } + + [HarmonyPatch(nameof(ItemAction.OnHUD)), MethodTargetPrefix] + public bool Prefix_OnHUD(ItemActionData _actionData) + { + if (_actionData.invData?.holdingEntity?.MinEventContext?.ItemActionData == null || _actionData.indexInEntityOfAction != _actionData.invData.holdingEntity.MinEventContext.ItemActionData.indexInEntityOfAction) + return false; + return true; + } + + //[MethodTargetPrefix(nameof(ItemActionAttack.ExecuteAction), typeof(ItemActionRanged))] + //public bool Prefix_ExecuteAction(ItemActionData _actionData, MultiActionData __customData) + //{ + // //when executing action, set last action index so that correct accuracy is used for drawing crosshair + // if (_actionData.invData.holdingEntity is EntityPlayerLocal player) + // { + // ((ItemActionRanged.ItemActionDataRanged)_actionData).lastAccuracy = __customData.lastAccuracy; + // } + // return true; + //} + + //[MethodTargetPrefix("updateAccuracy", typeof(ItemActionRanged))] + //public bool Prefix_updateAccuracy(ItemActionData _actionData, MultiActionData __customData) + //{ + // if (_actionData.invData.holdingEntity is EntityPlayerLocal player && MultiActionManager.GetActionIndexForEntityID(player.entityId) == _actionData.indexInEntityOfAction) + // return true; + // //always update custom accuracy + // ItemActionRanged.ItemActionDataRanged rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + // (rangedData.lastAccuracy, __customData.lastAccuracy) = (__customData.lastAccuracy, rangedData.lastAccuracy); + // return true; + //} + + //[MethodTargetPostfix("updateAccuracy", typeof(ItemActionRanged))] + //public void Postfix_updateAccuracy(ItemActionData _actionData, MultiActionData __customData) + //{ + // //retain rangedData accuracy if it's the last executed action + // ItemActionRanged.ItemActionDataRanged rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + // if (_actionData.invData.holdingEntity is EntityPlayerLocal player && MultiActionManager.GetActionIndexForEntityID(player.entityId) == _actionData.indexInEntityOfAction) + // { + // __customData.lastAccuracy = rangedData.lastAccuracy; + // } + // else + // { + // (rangedData.lastAccuracy, __customData.lastAccuracy) = (__customData.lastAccuracy, rangedData.lastAccuracy); + // } + //} + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.onHoldingEntityFired)), MethodTargetPrefix] + public bool Prefix_onHoldingEntityFired(ItemActionData _actionData) + { + if (!_actionData.invData.holdingEntity.isEntityRemote) + { + _actionData.invData.holdingEntity?.emodel?.avatarController.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, _actionData.indexInEntityOfAction); + //_actionData.invData.holdingEntity?.emodel?.avatarController.CancelEvent("WeaponFire"); + } + return true; + } + + //[MethodTargetPostfix("onHoldingEntityFired", typeof(ItemActionRanged))] + //public void Postfix_onHoldingEntityFired(ItemActionData _actionData, MultiActionData __customData) + //{ + // //after firing, if it's the last executed action then update custom accuracy + // if (_actionData.invData.holdingEntity is EntityPlayerLocal player && MultiActionManager.GetActionIndexForEntityID(player.entityId) == _actionData.indexInEntityOfAction) + // { + // __customData.lastAccuracy = ((ItemActionRanged.ItemActionDataRanged)_actionData).lastAccuracy; + // } + //} + + public static void SetAndSaveItemActionData(ItemActionData _actionData, out ItemActionData lastActionData) + { + lastActionData = _actionData.invData.holdingEntity.MinEventContext.ItemActionData; + _actionData.invData.holdingEntity.MinEventContext.ItemActionData = _actionData; + } + + public static void RestoreItemActionData(ItemActionData _actionData, ItemActionData lastActionData) + { + if (lastActionData != null) + _actionData.invData.holdingEntity.MinEventContext.ItemActionData = lastActionData; + } + + public class MultiActionData + { + public float lastAccuracy; + + public MultiActionData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleMultiActionFix _module) + { + + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Modular/ActionModuleMultiBarrel.cs b/Scripts/Items/Modular/ActionModuleMultiBarrel.cs new file mode 100644 index 0000000..72b245e --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleMultiBarrel.cs @@ -0,0 +1,302 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; +using System.Collections.Generic; +using System.Reflection.Emit; +using UniLinq; +using UnityEngine; + +[TypeTarget(typeof(ItemActionRanged)), ActionDataTarget(typeof(MultiBarrelData))] +public class ActionModuleMultiBarrel +{ + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + public void Postfix_OnModificationChanged(ItemActionData _data, MultiBarrelData __customData, ItemActionRanged __instance) + { + int actionIndex = _data.indexInEntityOfAction; + string originalValue = false.ToString(); + __instance.Properties.ParseString("MuzzleIsPerRound", ref originalValue); + __customData.muzzleIsPerRound = bool.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("MuzzleIsPerRound", originalValue, actionIndex)); + + originalValue = false.ToString(); + __instance.Properties.ParseString("OneRoundMultiShot", ref originalValue); + __customData.oneRoundMultishot = bool.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("OneRoundMultiShot", originalValue, actionIndex)); + + originalValue = 1.ToString(); + __instance.Properties.ParseString("RoundsPerShot", ref originalValue); + __customData.roundsPerShot = int.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("RoundsPerShot", originalValue, actionIndex)); + + originalValue = 1.ToString(); + __instance.Properties.ParseString("BarrelCount", ref originalValue); + __customData.barrelCount = int.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("BarrelCount", originalValue, actionIndex)); + + //Log.Out($"MuzzleIsPerRound: {__customData.muzzleIsPerRound} OneRoundMultiShot: {__customData.oneRoundMultishot} RoundsPerShot: {__customData.roundsPerShot} BarrelCount: {__customData.barrelCount}"); + + __customData.muzzles = new Transform[__customData.barrelCount]; + __customData.projectileJoints = new Transform[__customData.barrelCount]; + + for (int i = 0; i < __customData.barrelCount; i++) + { + string muzzleName = _data.invData.itemValue.GetPropertyOverrideForAction($"MBMuzzle{i}_Name", $"MBMuzzle{i}", actionIndex); + __customData.muzzles[i] = AnimationRiggingManager.GetTransformOverrideByName(_data.invData.model, muzzleName); + string jointName = _data.invData.itemValue.GetPropertyOverrideForAction($"MBProjectileJoint{i}_Name", $"MBProjectileJoint{i}", actionIndex); + __customData.projectileJoints[i] = AnimationRiggingManager.GetTransformOverrideByName(_data.invData.model, jointName); + } + + int meta = MultiActionUtils.GetMetaByActionIndex(_data.invData.itemValue, actionIndex); + __customData.SetCurrentBarrel(meta); + ((ItemActionRanged.ItemActionDataRanged)_data).IsDoubleBarrel = false; + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemAction.StartHolding)), MethodTargetPrefix] + public void Prefix_StartHolding_ItemActionLauncher(ItemActionData _data, ItemActionLauncher __instance, MultiBarrelData __customData) + { + ItemActionLauncher.ItemActionDataLauncher launcherData = _data as ItemActionLauncher.ItemActionDataLauncher; + launcherData.projectileJoint = __customData.projectileJoints[0]; + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemAction.StartHolding)), MethodTargetPostfix] + public void Postfix_StartHolding_ItemActionLauncher(ItemActionData _data, ItemActionLauncher __instance, MultiBarrelData __customData) + { + ItemActionLauncher.ItemActionDataLauncher launcherData = _data as ItemActionLauncher.ItemActionDataLauncher; + if (launcherData?.projectileInstance != null && __customData.oneRoundMultishot && __customData.roundsPerShot > 1) + { + int count = launcherData.projectileInstance.Count; + int times = __customData.roundsPerShot - 1; + for (int i = 0; i < times; i++) + { + launcherData.projectileJoint = __customData.projectileJoints[i + 1]; + for (int j = 0; j < count; j++) + { + launcherData.projectileInstance.Add(__instance.instantiateProjectile(_data)); + } + } + } + launcherData.projectileJoint = __customData.projectileJoints[__customData.curBarrelIndex]; + } + + [HarmonyPatch(nameof(ItemActionRanged.getUserData)), MethodTargetPostfix] + public void Postfix_getUserData(MultiBarrelData __customData, ref int __result) + { + __result |= ((byte)__customData.curBarrelIndex) << 8; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.ItemActionEffects)), MethodTargetPrefix] + public bool Prefix_ItemActionEffects_ItemActionRanged(ItemActionData _actionData, int _userData, int _firingState, MultiBarrelData __customData) + { + ItemActionRanged.ItemActionDataRanged rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + if (rangedData != null && _firingState != 0) + { + byte index = (byte)(_userData >> 8); + rangedData.muzzle = __customData.muzzles[index]; + __customData.SetAnimatorParam(index); + } + return true; + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemAction.ItemActionEffects)), MethodTargetPrefix] + public bool Prefix_ItemActionEffects_ItemActionLauncher(ItemActionData _actionData, int _userData, int _firingState, MultiBarrelData __customData) + { + ItemActionLauncher.ItemActionDataLauncher launcherData = _actionData as ItemActionLauncher.ItemActionDataLauncher; + if (launcherData != null) + { + launcherData.projectileJoint = __customData.projectileJoints[(byte)(_userData >> 8)]; + } + return Prefix_ItemActionEffects_ItemActionRanged(_actionData, _userData, _firingState, __customData); + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.ExecuteAction)), MethodTargetTranspiler] + private static IEnumerable Transpiler_ExecuteAction_ItemActionRanged(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + var mtd_getmax = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.GetMaxAmmoCount)); + var mtd_consume = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.ConsumeAmmo)); + var prop_instance = AccessTools.PropertyGetter(typeof(IModuleContainerFor), nameof(IModuleContainerFor.Instance)); + + Label loopStart = generator.DefineLabel(); + Label loopCondi = generator.DefineLabel(); + LocalBuilder lbd_data_module = generator.DeclareLocal(typeof(ActionModuleMultiBarrel.MultiBarrelData)); + LocalBuilder lbd_i = generator.DeclareLocal(typeof(int)); + LocalBuilder lbd_rounds = generator.DeclareLocal(typeof(int)); + for (int i = 0; i < codes.Count; i++) + { + //prepare loop and store local variables + if (codes[i].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 6) + { + codes[i + 1].WithLabels(loopStart); + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Castclass, typeof(IModuleContainerFor)), + new CodeInstruction(OpCodes.Callvirt, prop_instance), + new CodeInstruction(OpCodes.Stloc_S, lbd_data_module), + new CodeInstruction(OpCodes.Ldc_I4_0), + new CodeInstruction(OpCodes.Stloc_S, lbd_i), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.roundsPerShot)), + new CodeInstruction(OpCodes.Stloc_S, lbd_rounds), + new CodeInstruction(OpCodes.Br_S, loopCondi), + }); + i += 11; + } + //one round multi shot check + else if (codes[i].Calls(mtd_consume)) + { + Label lbl = generator.DefineLabel(); + codes[i - 5].WithLabels(lbl); + codes.InsertRange(i - 5, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.oneRoundMultishot)), + new CodeInstruction(OpCodes.Brfalse_S, lbl), + new CodeInstruction(OpCodes.Ldloc_S, lbd_i), + new CodeInstruction(OpCodes.Ldc_I4_0), + new CodeInstruction(OpCodes.Bgt_S, codes[i - 3].operand) + }); + i += 6; + } + //loop conditions and cycle barrels + else if (codes[i].Calls(mtd_getmax)) + { + Label lbl_pre = generator.DefineLabel(); + Label lbl_post = generator.DefineLabel(); + CodeInstruction origin = codes[i - 2]; + codes.InsertRange(i - 2, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module).WithLabels(origin.ExtractLabels()), + CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.muzzleIsPerRound)), + new CodeInstruction(OpCodes.Brfalse_S, lbl_pre), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.Call(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.CycleBarrels)), + new CodeInstruction(OpCodes.Ldloc_S, 6).WithLabels(lbl_pre), + CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.inventory)), + CodeInstruction.Call(typeof(Inventory), nameof(Inventory.CallOnToolbeltChangedInternal)), + new CodeInstruction(OpCodes.Ldloc_S, lbd_i), + new CodeInstruction(OpCodes.Ldc_I4_1), + new CodeInstruction(OpCodes.Add), + new CodeInstruction(OpCodes.Stloc_S, lbd_i), + new CodeInstruction(OpCodes.Ldloc_S, lbd_i).WithLabels(loopCondi), + new CodeInstruction(OpCodes.Ldloc_S, lbd_rounds), + new CodeInstruction(OpCodes.Blt_S, loopStart), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.muzzleIsPerRound)), + new CodeInstruction(OpCodes.Brtrue_S, lbl_post), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.Call(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.CycleBarrels)) + }); + origin.WithLabels(lbl_post); + break; + } + } + + return codes; + } + + private static void LogInfo(int cur, int max) => Log.Out($"max rounds {max}, cur {cur}"); + + public class MultiBarrelData + { + public ItemInventoryData invData; + public int actionIndex; + public ActionModuleMultiBarrel module; + public bool muzzleIsPerRound; + public bool oneRoundMultishot; + public int roundsPerShot; + public int barrelCount; + public int curBarrelIndex; + public Transform[] muzzles; + public Transform[] projectileJoints; + + public MultiBarrelData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleMultiBarrel _module) + { + invData = _invData; + actionIndex = _indexInEntityOfAction; + module = _module; + } + + public void CycleBarrels() + { + curBarrelIndex = ++curBarrelIndex >= barrelCount ? 0 : curBarrelIndex; + //Log.Out($"cycle barrel index {curBarrelIndex}"); + } + + public void SetCurrentBarrel(int roundLeft) + { + if (muzzleIsPerRound) + { + int totalSwitches; + if (oneRoundMultishot) + { + totalSwitches = roundLeft * roundsPerShot; + } + else + { + totalSwitches = roundLeft; + } + int lastCycleSwitches = totalSwitches % barrelCount; + int barrelGroup = barrelCount / roundsPerShot; + curBarrelIndex = (barrelCount - lastCycleSwitches) / barrelGroup * barrelGroup; + } + else + { + if (oneRoundMultishot) + { + curBarrelIndex = barrelCount - (roundLeft % barrelCount); + } + else + { + curBarrelIndex = barrelCount - ((roundLeft + 1) / roundsPerShot) % barrelCount; + } + } + if (curBarrelIndex >= barrelCount) + { + curBarrelIndex = 0; + } + SetAnimatorParam(curBarrelIndex); + //Log.Out($"set barrel index {curBarrelIndex}"); + } + + public void SetAnimatorParam(int barrelIndex) + { + invData.holdingEntity.emodel.avatarController.UpdateInt("barrelIndex", barrelIndex, true); + //Log.Out($"set param index {barrelIndex}"); + } + } +} + +[HarmonyPatch] +public class MultiBarrelPatches +{ + + [HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateEnter))] + [HarmonyPostfix] + private static void Postfix_OnStateEnter_AnimatorRangedReloadState(AnimatorRangedReloadState __instance) + { + ItemActionLauncher.ItemActionDataLauncher launcherData = __instance.actionData as ItemActionLauncher.ItemActionDataLauncher; + if (launcherData != null && launcherData is IModuleContainerFor dataModule && dataModule.Instance.oneRoundMultishot && dataModule.Instance.roundsPerShot > 1) + { + int count = launcherData.projectileInstance.Count; + int times = dataModule.Instance.roundsPerShot - 1; + for (int i = 0; i < count; i++) + { + for (int j = 0; j < times; j++) + { + launcherData.projectileJoint = dataModule.Instance.projectileJoints[j + 1]; + launcherData.projectileInstance.Insert(i * (times + 1) + j + 1, ((ItemActionLauncher)__instance.actionRanged).instantiateProjectile(launcherData)); + } + } + } + } + + [HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateExit))] + [HarmonyPostfix] + private static void Postfix_OnStateExit_AnimatorRangedReloadState(AnimatorRangedReloadState __instance) + { + if (__instance.actionData is IModuleContainerFor dataModule) + { + dataModule.Instance.SetCurrentBarrel(__instance.actionData.invData.itemValue.Meta); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Modular/ActionModuleRampUp.cs b/Scripts/Items/Modular/ActionModuleRampUp.cs new file mode 100644 index 0000000..cbca03c --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleRampUp.cs @@ -0,0 +1,276 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.Utilities; +using UnityEngine; +using static ItemActionRanged; + +[TypeTarget(typeof(ItemActionRanged)), ActionDataTarget(typeof(RampUpData))] +public class ActionModuleRampUp +{ + public enum State + { + RampUp, + Stable, + RampDown + } + + private readonly static int prepareHash = Animator.StringToHash("prepare"); + private readonly static int prepareSpeedHash = Animator.StringToHash("prepareSpeed"); + private readonly static int rampHash = Animator.StringToHash("ramp"); + private readonly static int prepareRatioHash = Animator.StringToHash("prepareRatio"); + private readonly static int rampRatioHash = Animator.StringToHash("rampRatio"); + private readonly static int totalRatioHash = Animator.StringToHash("totalRatio"); + + [HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPostfix] + public void Postfix_OnHoldingUpdate(ItemActionData _actionData, RampUpData __customData, ItemActionRanged __instance) + { + var rangedData = _actionData as ItemActionDataRanged; + __customData.originalDelay = rangedData.Delay; + if (rangedData.invData.holdingEntity.isEntityRemote) + return; + + bool aiming = rangedData.invData.holdingEntity.AimingGun; + bool isRampUp = ((rangedData.bPressed && !rangedData.bReleased && __instance.notReloading(rangedData) && rangedData.curBurstCount < __instance.GetBurstCount(rangedData)) || (__customData.zoomPrepare && aiming)) && (__instance.InfiniteAmmo || _actionData.invData.itemValue.Meta > 0) && _actionData.invData.itemValue.PercentUsesLeft > 0; + UpdateTick(__customData, _actionData, isRampUp); + if (__customData.rampRatio > 0) + { + rangedData.Delay /= __customData.rampRatio >= 1f ? __customData.maxMultiplier : __customData.rampRatio * (__customData.maxMultiplier - 1f) + 1f; + } + } + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + public void Postfix_OnModificationsChanged(ItemActionData _data, RampUpData __customData, ItemActionRanged __instance) + { + int actionIndex = __instance.ActionIndex; + string originalValue = 1.ToString(); + __instance.Properties.ParseString("RampMultiplier", ref originalValue); + __customData.maxMultiplier = Mathf.Max(float.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("RampMultiplier", originalValue, actionIndex)), 1); + + originalValue = 0.ToString(); + __instance.Properties.ParseString("RampUpTime", ref originalValue); + __customData.rampUpTime = float.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("RampTime", originalValue, actionIndex)); + + originalValue = string.Empty; + __instance.Properties.ParseString("RampUpSound", ref originalValue); + __customData.rampUpSound = _data.invData.itemValue.GetPropertyOverrideForAction("RampStartSound", originalValue, actionIndex); + + originalValue = 0.ToString(); + __instance.Properties.ParseString("RampDownTime", ref originalValue); + __customData.rampDownTime = Mathf.Max(float.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("RampTime", originalValue, actionIndex)), 0); + + originalValue = string.Empty; + __instance.Properties.ParseString("RampDownSound", ref originalValue); + __customData.rampDownSound = _data.invData.itemValue.GetPropertyOverrideForAction("RampStartSound", originalValue, actionIndex); + + originalValue = 0.ToString(); + __instance.Properties.ParseString("PrepareTime", ref originalValue); + __customData.prepareTime = float.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("PrepareTime", originalValue, actionIndex)); + __customData.prepareSpeed = float.Parse(originalValue) / __customData.prepareTime; + + originalValue = string.Empty; + __instance.Properties.ParseString("PrepareSound", ref originalValue); + __customData.prepareSound = _data.invData.itemValue.GetPropertyOverrideForAction("PrepareSound", originalValue, actionIndex); + + originalValue = false.ToString(); + __instance.Properties.ParseString("PrepareOnAim", ref originalValue); + __customData.zoomPrepare = bool.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("PrepareOnAim", originalValue, actionIndex)); + + originalValue = string.Empty; + __instance.Properties.ParseString("RampStableSound", ref originalValue); + __customData.rampStableSound = _data.invData.itemValue.GetPropertyOverrideForAction("RampStableSound", originalValue, actionIndex); + + __customData.totalChargeTime = __customData.prepareTime + __customData.rampUpTime; + __customData.rampDownTimeScale = __customData.rampDownTime > 0 ? (__customData.totalChargeTime) / __customData.rampDownTime : float.MaxValue; + + ResetAll(__customData, _data); + } + + [HarmonyPatch(nameof(ItemAction.StopHolding)), MethodTargetPostfix] + public void Postfix_StopHolding(RampUpData __customData, ItemActionData _data) + { + ResetAll(__customData, _data); + } + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPrefix] + public bool Prefix_ExecuteAction(RampUpData __customData, ItemActionRanged __instance, ItemActionData _actionData, bool _bReleased) + { + ItemActionDataRanged rangedData = _actionData as ItemActionDataRanged; + if (!_bReleased && (__instance.InfiniteAmmo || _actionData.invData.itemValue.Meta > 0) && _actionData.invData.itemValue.PercentUsesLeft > 0) + { + rangedData.bReleased = false; + rangedData.bPressed = true; + if (__customData.curTime < __customData.prepareTime) + return false; + } + return true; + } + + private void UpdateTick(RampUpData data, ItemActionData actionData, bool isRampUp) + { + float previousTime = data.curTime; + float deltaTime = Time.time - data.lastTickTime; + data.lastTickTime = Time.time; + ref float curTime = ref data.curTime; + ref State curState = ref data.curState; + float totalChargeTime = data.totalChargeTime; + switch (curState) + { + case State.RampUp: + { + curTime = Mathf.Max(curTime, 0); + if (isRampUp) + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(prepareHash, true, true); + if (curTime < totalChargeTime) + { + curTime += deltaTime; + } + if (curTime >= data.prepareTime) + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(rampHash, true, true); + } + if (curTime >= totalChargeTime) + { + //Log.Out($"change state from {curState} to stable"); + actionData.invData.holdingEntity.PlayOneShot(data.rampStableSound); + curState = State.Stable; + } + } + else + { + //Log.Out($"change state from {curState} to ramp down"); + actionData.invData.holdingEntity.StopOneShot(data.rampUpSound); + actionData.invData.holdingEntity.PlayOneShot(data.rampDownSound); + curState = State.RampDown; + } + break; + } + case State.RampDown: + { + curTime = Mathf.Min(curTime, totalChargeTime); + if (!isRampUp) + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(rampHash, false, true); + if (curTime > 0) + { + curTime -= deltaTime * data.rampDownTimeScale; + } + if (curTime < data.prepareTime) + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(prepareHash, false, true); + } + if (curTime <= 0) + { + //Log.Out($"change state from {curState} to stable"); + //actionData.invData.holdingEntity.PlayOneShot(data.rampStableSound); + curState = State.Stable; + } + } + else + { + //Log.Out($"change state from {curState} to ramp up"); + actionData.invData.holdingEntity.StopOneShot(data.rampDownSound); + actionData.invData.holdingEntity.PlayOneShot(data.rampUpSound); + curState = State.RampUp; + } + break; + } + case State.Stable: + { + if (isRampUp) + { + if (curTime < totalChargeTime) + { + //Log.Out($"change state from {curState} to ramp up"); + actionData.invData.holdingEntity.StopOneShot(data.rampStableSound); + actionData.invData.holdingEntity.StopOneShot(data.rampDownSound); + actionData.invData.holdingEntity.PlayOneShot(data.rampUpSound); + curState = State.RampUp; + } + else + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(prepareHash, true, true); + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(rampHash, true, true); + } + } + else + { + if (curTime > 0) + { + //Log.Out($"change state from {curState} to ramp down"); + actionData.invData.holdingEntity.StopOneShot(data.rampStableSound); + actionData.invData.holdingEntity.StopOneShot(data.rampUpSound); + actionData.invData.holdingEntity.PlayOneShot(data.rampDownSound); + curState = State.RampDown; + } + else + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(prepareHash, false, true); + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(rampHash, false, true); + } + } + break; + } + } + //Log.Out($"turret burst fire rate {turret.burstFireRate} max {turret.burstFireRateMax} cur time {curTime} cur state {curState} is ramp up {isRampUp} turret: ison {turret.IsOn} has target {turret.hasTarget} state {turret.state}"); + actionData.invData.holdingEntity.emodel.avatarController.UpdateFloat(prepareSpeedHash, data.prepareSpeed); + if (curTime != previousTime) + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateFloat(prepareRatioHash, data.prepareRatio = (data.prepareTime == 0 ? 1f : Mathf.Clamp01(curTime / data.prepareTime))); + actionData.invData.holdingEntity.emodel.avatarController.UpdateFloat(rampRatioHash, data.rampRatio = (data.rampUpTime == 0 ? 1f : Mathf.Clamp01((curTime - data.prepareTime) / data.rampUpTime))); + actionData.invData.holdingEntity.emodel.avatarController.UpdateFloat(totalRatioHash, data.totalRatio = (totalChargeTime == 0 ? 1f : Mathf.Clamp01(curTime / totalChargeTime))); + } + } + + private void ResetAll(RampUpData _rampData, ItemActionData _actionData) + { + _rampData.curTime = 0f; + _rampData.lastTickTime = Time.time; + _rampData.curState = State.Stable; + _rampData.prepareRatio = 0f; + _rampData.rampRatio = 0f; + _rampData.totalRatio = 0f; + ((ItemActionDataRanged)_actionData).Delay = _rampData.originalDelay; + _actionData.invData.holdingEntity.StopOneShot(_rampData.prepareSound); + _actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(prepareHash, false, true); + _actionData.invData.holdingEntity.StopOneShot(_rampData.rampUpSound); + _actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(rampHash, false, true); + //Log.Out("Reset all!"); + } + + public class RampUpData + { + public float maxMultiplier = 1f; + + public string prepareSound = string.Empty; + public float prepareSpeed = 1f; + public float prepareTime = 0f; + + public string rampUpSound = string.Empty; + public float rampUpTime = 0f; + public float totalChargeTime = 0f; + + public string rampDownSound = string.Empty; + public float rampDownTime = 0f; + public float rampDownTimeScale = float.MaxValue; + + public string rampStableSound = string.Empty; + + public float originalDelay = 0f; + public float curTime = 0f; + public State curState = State.Stable; + public float prepareRatio = 0f; + public float rampRatio = 0f; + public float totalRatio = 0f; + public float lastTickTime = 0f; + + public bool zoomPrepare = false; + + public ActionModuleRampUp rampUpModule; + + public RampUpData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleRampUp _module) + { + rampUpModule = _module; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/Modular/ActionModuleTagged.cs b/Scripts/Items/Modular/ActionModuleTagged.cs new file mode 100644 index 0000000..b4a7dd8 --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleTagged.cs @@ -0,0 +1,30 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.Utilities; +using UniLinq; + +[TypeTarget(typeof(ItemAction)), ActionDataTarget(typeof(TaggedData))] +public class ActionModuleTagged +{ + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationChanged(ItemAction __instance, ItemActionData _data, TaggedData __customData) + { + var tags = __instance.Properties.GetString("ActionTags").Split(',', System.StringSplitOptions.RemoveEmptyEntries); + var tags_to_add = _data.invData.itemValue.GetAllPropertyOverridesForAction("ActionTagsAppend", __instance.ActionIndex).SelectMany(s => s.Split(',', System.StringSplitOptions.RemoveEmptyEntries)); + var tags_to_remove = _data.invData.itemValue.GetAllPropertyOverridesForAction("ActionTagsRemove", __instance.ActionIndex).SelectMany(s => s.Split(',', System.StringSplitOptions.RemoveEmptyEntries)); + var tags_result = tags.Union(tags_to_add); + tags_result = tags_result.Except(tags_to_remove); + + __customData.tags = tags_result.Any() ? FastTags.Parse(string.Join(",", tags_result)) : FastTags.none; + //Log.Out($"tags: {string.Join(",", tags_result)}"); + } + + public class TaggedData + { + public FastTags tags; + public TaggedData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleTagged _module) + { + + } + } +} diff --git a/Scripts/Items/Modular/ActionModuleTranspilerTest.cs b/Scripts/Items/Modular/ActionModuleTranspilerTest.cs new file mode 100644 index 0000000..6a482fa --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleTranspilerTest.cs @@ -0,0 +1,48 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using System.Collections.Generic; +using System.Reflection.Emit; +using UnityEngine; + +[TypeTarget(typeof(ItemAction))] +public class ActionModuleTranspilerTest +{ + [HarmonyPatch(typeof(ItemActionAttack), nameof(ItemAction.ExecuteAction)), MethodTargetTranspiler] + private static IEnumerable Transpiler_InvalidTest(IEnumerable instructions) + { + yield return new CodeInstruction(OpCodes.Ldstr, "Ranged!"); + yield return CodeInstruction.Call(typeof(ActionModuleTranspilerTest), nameof(ActionModuleTranspilerTest.CallSomething)); + foreach (var ins in instructions) + { + yield return ins; + } + } + + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.ExecuteAction)), MethodTargetTranspiler] + private static IEnumerable Transpiler_RangedTest(IEnumerable instructions) + { + yield return new CodeInstruction(OpCodes.Ldstr, "Ranged!"); + yield return CodeInstruction.Call(typeof(ActionModuleTranspilerTest), nameof(ActionModuleTranspilerTest.CallSomething)); + foreach (var ins in instructions) + { + yield return ins; + } + } + + [HarmonyPatch(typeof(ItemActionCatapult), nameof(ItemAction.ExecuteAction)), MethodTargetTranspiler] + private static IEnumerable Transpiler_CatapultTest(IEnumerable instructions) + { + yield return new CodeInstruction(OpCodes.Ldstr, "Catapult!"); + yield return CodeInstruction.Call(typeof(ActionModuleTranspilerTest), nameof(ActionModuleTranspilerTest.CallSomething)); + foreach (var ins in instructions) + { + yield return ins; + } + } + + private static void CallSomething(string str) + { + Log.Out($"Call something: {str}\n{StackTraceUtility.ExtractStackTrace()}"); + } +} \ No newline at end of file diff --git a/Scripts/Items/Modular/ActionModuleVariableZoom.cs b/Scripts/Items/Modular/ActionModuleVariableZoom.cs new file mode 100644 index 0000000..47bbff2 --- /dev/null +++ b/Scripts/Items/Modular/ActionModuleVariableZoom.cs @@ -0,0 +1,73 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using UnityEngine; + +[TypeTarget(typeof(ItemActionZoom)), ActionDataTarget(typeof(VariableZoomData))] +public class ActionModuleVariableZoom +{ + public static float zoomScale = 7.5f; + [HarmonyPatch(nameof(ItemAction.ConsumeScrollWheel)), MethodTargetPostfix] + private void Postfix_ConsumeScrollWheel(ItemActionData _actionData, float _scrollWheelInput, PlayerActionsLocal _playerInput, VariableZoomData __customData) + { + if (!_actionData.invData.holdingEntity.AimingGun || _scrollWheelInput == 0f) + { + return; + } + + ItemActionZoom.ItemActionDataZoom itemActionDataZoom = (ItemActionZoom.ItemActionDataZoom)_actionData; + if (!itemActionDataZoom.bZoomInProgress) + { + //__customData.curScale = Utils.FastClamp(__customData.curScale + _scrollWheelInput * zoomScale, __customData.minScale, __customData.maxScale); + __customData.curSteps = Utils.FastClamp01(__customData.curSteps + _scrollWheelInput); + __customData.curFov = Utils.FastLerp(__customData.maxFov, __customData.minFov, GetNext(__customData.curSteps)); + __customData.curScale = Mathf.Pow(Mathf.Rad2Deg * 2 * Mathf.Atan(Mathf.Tan(Mathf.Deg2Rad * 7.5f) / __customData.curFov), 2); + __customData.shouldUpdate = true; + } + } + + private float GetNext(float cur) + { + return Mathf.Sin(Mathf.PI * cur / 2); + } + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationChanged(ItemActionZoom __instance, ItemActionData _data, VariableZoomData __customData) + { + string str = __instance.Properties.GetString("ZoomRatio"); + if (string.IsNullOrEmpty(str)) + { + str = "1"; + } + __customData.maxScale = StringParsers.ParseFloat(_data.invData.itemValue.GetPropertyOverride("ZoomRatio", str)); + + str = __instance.Properties.GetString("ZoomRatioMin"); + if (string.IsNullOrEmpty(str)) + { + str = __customData.maxScale.ToString(); + } + __customData.minScale = StringParsers.ParseFloat(_data.invData.itemValue.GetPropertyOverride("ZoomRatioMin", str)); + //__customData.curScale = Utils.FastClamp(__customData.curScale, __customData.minScale, __customData.maxScale); + __customData.maxFov = Mathf.Rad2Deg * 2 * Mathf.Atan(Mathf.Tan(Mathf.Deg2Rad * 7.5f) / Mathf.Sqrt(__customData.minScale)); + __customData.minFov = Mathf.Rad2Deg * 2 * Mathf.Atan(Mathf.Tan(Mathf.Deg2Rad * 7.5f) / Mathf.Sqrt(__customData.maxScale)); + __customData.curFov = Utils.FastClamp(__customData.curFov, __customData.minFov, __customData.maxFov); + __customData.curScale = Mathf.Pow(Mathf.Rad2Deg * 2 * Mathf.Atan(Mathf.Tan(Mathf.Deg2Rad * 7.5f) / __customData.curFov), 2); + __customData.curSteps = Mathf.InverseLerp(__customData.maxFov, __customData.minFov, __customData.curFov); + __customData.shouldUpdate = true; + } + + public class VariableZoomData + { + public float maxScale = 1f; + public float minScale = 1f; + public float curScale = 0f; + public float maxFov = 15f; + public float minFov = 15f; + public float curFov = 90f; + public float curSteps = 0; + public bool shouldUpdate = true; + public VariableZoomData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleVariableZoom _module) + { + + } + } +} diff --git a/Scripts/Items/ModularActions/ActionModuleAlternative.cs b/Scripts/Items/ModularActions/ActionModuleAlternative.cs new file mode 100644 index 0000000..abc647f --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleAlternative.cs @@ -0,0 +1,261 @@ +using GUI_2; +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; +using System.Collections; +using Unity.Mathematics; + +[TypeTarget(typeof(ItemActionAttack)), ActionDataTarget(typeof(AlternativeData))] +public class ActionModuleAlternative +{ + internal static ItemValue InventorySetItemTemp; + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPrefix] + private bool Prefix_StartHolding(ItemActionData _data, AlternativeData __customData) + { + //__customData.Init(); + int prevMode = __customData.mapping.CurMode; + __customData.UpdateUnlockState(_data.invData.itemValue); + if (prevMode != __customData.mapping.CurMode && _data.invData.holdingEntity is EntityPlayerLocal player) + { + MultiActionManager.FireToggleModeEvent(player, __customData.mapping); + } + MultiActionManager.SetMappingForEntity(_data.invData.holdingEntity.entityId, __customData.mapping); + if (_data.invData.holdingEntity is EntityPlayerLocal) + { + MultiActionManager.inputCD = math.max(0.5f, MultiActionManager.inputCD); + //ThreadManager.StartCoroutine(DelaySetExecutionIndex(_data.invData.holdingEntity, __customData.mapping)); + } + return true; + } + + //[MethodTargetPostfix(nameof(ItemActionAttack.StartHolding))] + //private void Postfix_StartHolding(AlternativeData __customData) + //{ + // __customData.UpdateMuzzleTransformOverride(); + // __customData.OverrideMuzzleTransform(__customData.mapping.CurMode); + //} + + private static IEnumerator DelaySetExecutionIndex(EntityAlive player, MultiActionMapping mapping) + { + yield return null; + yield return null; + if (GameManager.Instance.GetGameStateManager().IsGameStarted()) + player?.emodel?.avatarController?.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, mapping.CurActionIndex); + } + + [HarmonyPatch(nameof(ItemActionRanged.CancelReload)), MethodTargetPrefix] + private bool Prefix_CancelReload(ItemActionData _actionData, AlternativeData __customData) + { + if (__customData.mapping == null) + return true; + int actionIndex = __customData.mapping.CurActionIndex; + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"cancel reload {actionIndex}"); + if (actionIndex == 0) + return true; + _actionData.invData.holdingEntity.inventory.holdingItem.Actions[actionIndex].CancelReload(_actionData.invData.holdingEntity.inventory.holdingItemData.actionData[actionIndex]); + return false; + } + + [HarmonyPatch(nameof(ItemAction.CancelAction)), MethodTargetPrefix] + private bool Prefix_CancelAction(ItemActionData _actionData, AlternativeData __customData) + { + if (__customData.mapping == null) + return true; + int actionIndex = __customData.mapping.CurActionIndex; + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"cancel action {actionIndex}"); + if (actionIndex == 0) + return true; + _actionData.invData.holdingEntity.inventory.holdingItem.Actions[actionIndex].CancelAction(_actionData.invData.holdingEntity.inventory.holdingItemData.actionData[actionIndex]); + return false; + } + + [HarmonyPatch(nameof(ItemAction.IsStatChanged)), MethodTargetPrefix] + private bool Prefix_IsStatChanged(ref bool __result) + { + var mapping = MultiActionManager.GetMappingForEntity(GameManager.Instance.World.GetPrimaryPlayerId()); + __result |= mapping != null && mapping.CheckDisplayMode(); + return false; + } + + //[MethodTargetPostfix(nameof(ItemActionAttack.StopHolding))] + //private void Postfix_StopHolding(AlternativeData __customData) + //{ + // //moved to harmony patch + // //MultiActionManager.SetMappingForEntity(_data.invData.holdingEntity.entityId, null); + // __customData.mapping.SaveMeta(); + //} + + //todo: change to action specific property + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationChanged(ItemActionData _data, ItemActionAttack __instance, AlternativeData __customData) + { + __instance.Properties.ParseString("ToggleActionSound", ref __customData.toggleSound); + __customData.toggleSound = _data.invData.itemValue.GetPropertyOverrideForAction("ToggleActionSound", __customData.toggleSound, __instance.ActionIndex); + __customData.mapping.toggleSound = __customData.toggleSound; + } + + [HarmonyPatch(nameof(ItemAction.SetupRadial)), MethodTargetPrefix] + private bool Prefix_SetupRadial(XUiC_Radial _xuiRadialWindow, EntityPlayerLocal _epl) + { + var mapping = MultiActionManager.GetMappingForEntity(_epl.entityId); + if (mapping != null) + { + var radialContextItem = new AlternativeRadialContextItem(mapping, _xuiRadialWindow, _epl); + _xuiRadialWindow.SetCommonData(UIUtils.GetButtonIconForAction(_epl.playerInput.Reload), handleRadialCommand, radialContextItem, radialContextItem.PreSelectedIndex, false, radialValidTest); + } + + return false; + } + + private bool radialValidTest(XUiC_Radial _sender, XUiC_Radial.RadialContextAbs _context) + { + AlternativeRadialContextItem radialContextItem = _context as AlternativeRadialContextItem; + if (radialContextItem == null) + { + return false; + } + EntityPlayerLocal entityPlayer = _sender.xui.playerUI.entityPlayer; + return radialContextItem.mapping == MultiActionManager.GetMappingForEntity(entityPlayer.entityId) && radialContextItem.mapping.CurActionIndex == radialContextItem.ActionIndex; + } + + //redirect reload call to shared meta action, which then sets ItemActionIndex animator param to its action index + //for example if action 3 share meta with action 0, then ItemActionIndex is set to 0 on reload begin. + //since event param item action data is set to the shared meta action data, all reload related passive calculation and trigger events goes there. + private void handleRadialCommand(XUiC_Radial _sender, int _commandIndex, XUiC_Radial.RadialContextAbs _context) + { + AlternativeRadialContextItem radialContextItem = _context as AlternativeRadialContextItem; + if (radialContextItem == null) + { + return; + } + EntityPlayerLocal entityPlayer = _sender.xui.playerUI.entityPlayer; + if (radialContextItem.mapping == MultiActionManager.GetMappingForEntity(entityPlayer.entityId) && radialContextItem.mapping.CurActionIndex == radialContextItem.ActionIndex) + { + entityPlayer.MinEventContext.ItemActionData = entityPlayer.inventory.holdingItemData.actionData?[radialContextItem.ActionIndex]; + (entityPlayer.inventory.holdingItem.Actions?[radialContextItem.ActionIndex] as ItemActionRanged)?.SwapSelectedAmmo(entityPlayer, _commandIndex); + } + } + + public class AlternativeData + { + public MultiActionMapping mapping; + public string toggleSound; + public ItemInventoryData invData; + //private bool inited = false; + private readonly bool[] unlocked = new bool[MultiActionIndice.MAX_ACTION_COUNT]; + //public Transform[] altMuzzleTrans = new Transform[MultiActionIndice.MAX_ACTION_COUNT]; + //public Transform[] altMuzzleTransDBarrel = new Transform[MultiActionIndice.MAX_ACTION_COUNT]; + + public AlternativeData(ItemInventoryData invData, int actionIndex, ActionModuleAlternative module) + { + this.invData = invData; + Init(); + + } + + //public void UpdateMuzzleTransformOverride() + //{ + // for (int i = 0; i < MultiActionIndice.MAX_ACTION_COUNT; i++) + // { + // int curActionIndex = mapping.indices.GetActionIndexForMode(i); + // if (curActionIndex < 0) + // { + // break; + // } + // var rangedData = invData.actionData[curActionIndex] as ItemActionRanged.ItemActionDataRanged; + // if (rangedData != null) + // { + // if (rangedData.IsDoubleBarrel) + // { + // altMuzzleTrans[i] = AnimationRiggingManager.GetTransformOverrideByName($"Muzzle_L{curActionIndex}", rangedData.invData.model) ?? rangedData.muzzle; + // altMuzzleTransDBarrel[i] = AnimationRiggingManager.GetTransformOverrideByName($"Muzzle_R{curActionIndex}", rangedData.invData.model) ?? rangedData.muzzle2; + // } + // else + // { + // altMuzzleTrans[i] = AnimationRiggingManager.GetTransformOverrideByName($"Muzzle{curActionIndex}", rangedData.invData.model) ?? rangedData.muzzle; + // } + // } + // } + //} + + public void Init() + { + //if (inited) + // return; + + //inited = true; + MultiActionIndice indices = MultiActionManager.GetActionIndiceForItemID(invData.item.Id); + mapping = new MultiActionMapping(this, indices, invData.holdingEntity, InventorySetItemTemp, toggleSound, invData.slotIdx, unlocked); + UpdateUnlockState(InventorySetItemTemp); + } + + public void UpdateUnlockState(ItemValue itemValue) + { + //if (!inited) + // return; + unlocked[0] = true; + for (int i = 1; i < mapping.ModeCount; i++) + { + bool flag = true; + int actionIndex = mapping.indices.GetActionIndexForMode(i); + ItemAction action = itemValue.ItemClass.Actions[actionIndex]; + action.Properties.ParseBool("ActionUnlocked", ref flag); + if (bool.TryParse(itemValue.GetPropertyOverride($"ActionUnlocked_{actionIndex}", flag.ToString()), out bool overrideFlag)) + flag = overrideFlag; + unlocked[i] = flag; + } + //by the time we check unlock state, ItemValue in inventory slot might not be ready yet + mapping.SaveMeta(itemValue); + mapping.CurMode = mapping.CurMode; + mapping.ReadMeta(itemValue); + } + + public bool IsActionUnlocked(int actionIndex) + { + int mode = mapping.indices.GetModeForAction(actionIndex); + if (mode >= MultiActionIndice.MAX_ACTION_COUNT || mode < 0) + return false; + return unlocked[mode]; + } + +// public void OverrideMuzzleTransform(int mode) +// { +// var rangedData = invData.actionData[mapping.indices.GetActionIndexForMode(mode)] as ItemActionRanged.ItemActionDataRanged; +// if (rangedData != null) +// { +// if (rangedData.IsDoubleBarrel) +// { +// rangedData.muzzle = altMuzzleTrans[mode]; +// rangedData.muzzle2 = altMuzzleTransDBarrel[mode]; +// } +// else +// { +// rangedData.muzzle = altMuzzleTrans[mode]; +// } +// } +//#if DEBUG +// Log.Out($"setting muzzle transform for action {rangedData.indexInEntityOfAction} to {rangedData.muzzle.name}\n{StackTraceUtility.ExtractStackTrace()}"); +//#endif +// } + } + + //todo: don't setup for every mode, and use reload animation from shared action + public class AlternativeRadialContextItem : XUiC_Radial.RadialContextAbs + { + public MultiActionMapping mapping; + + public int ActionIndex { get; private set; } + public int PreSelectedIndex { get; private set; } + + public AlternativeRadialContextItem(MultiActionMapping mapping, XUiC_Radial _xuiRadialWindow, EntityPlayerLocal _epl) + { + this.mapping = mapping; + ActionIndex = mapping.CurActionIndex; + PreSelectedIndex = mapping.SetupRadial(_xuiRadialWindow, _epl); + } + } +} diff --git a/Scripts/Items/ModularActions/ActionModuleAnimationLocked.cs b/Scripts/Items/ModularActions/ActionModuleAnimationLocked.cs new file mode 100644 index 0000000..3d93ce9 --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleAnimationLocked.cs @@ -0,0 +1,36 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; + +[TypeTarget(typeof(ItemAction)), ActionDataTarget(typeof(AnimationLockedData))] +public class ActionModuleAnimationLocked +{ + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPostfix] + private void Postfix_StartHolding(AnimationLockedData __customData) + { + __customData.isLocked = false; + __customData.isReloadLocked = false; + } + + [HarmonyPatch(nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning(AnimationLockedData __customData, ref bool __result) + { + __result |= __customData.isLocked; + } + + [HarmonyPatch(typeof(ItemActionAttack), nameof(ItemActionAttack.CanReload)), MethodTargetPostfix] + private void Postfix_CanReload_ItemActionAttack(AnimationLockedData __customData, ref bool __result) + { + __result &= !__customData.isReloadLocked; + } + + public class AnimationLockedData + { + public bool isLocked = false; + public bool isReloadLocked = false; + + public AnimationLockedData(ItemInventoryData invData, int actionIndex, ActionModuleAnimationLocked module) + { + + } + } +} diff --git a/Scripts/Items/ModularActions/ActionModuleCustomAnimationDelay.cs b/Scripts/Items/ModularActions/ActionModuleCustomAnimationDelay.cs new file mode 100644 index 0000000..66dc1db --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleCustomAnimationDelay.cs @@ -0,0 +1,135 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using System.Collections.Generic; +using System.Reflection.Emit; +using UniLinq; +using static AnimationDelayData; + +[TypeTarget(typeof(ItemAction))] +public class ActionModuleCustomAnimationDelay +{ + [HarmonyPatch(typeof(ItemActionEat), nameof(ItemAction.OnHoldingUpdate))] + [HarmonyPatch(typeof(ItemActionGainSkill), nameof(ItemAction.OnHoldingUpdate))] + [HarmonyPatch(typeof(ItemActionLearnRecipe), nameof(ItemAction.OnHoldingUpdate))] + [HarmonyPatch(typeof(ItemActionQuest), nameof(ItemAction.OnHoldingUpdate))] + [HarmonyPatch(typeof(ItemActionEat), nameof(ItemAction.IsActionRunning))] + [HarmonyPatch(typeof(ItemActionGainSkill), nameof(ItemAction.IsActionRunning))] + [HarmonyPatch(typeof(ItemActionLearnRecipe), nameof(ItemAction.IsActionRunning))] + [HarmonyPatch(typeof(ItemActionQuest), nameof(ItemAction.IsActionRunning))] + [MethodTargetTranspiler] + private static IEnumerable Transpiler_OnHoldingUpdate(IEnumerable instructions) + { + var codes = instructions.ToList(); + var fld_delayarr = AccessTools.Field(typeof(AnimationDelayData), nameof(AnimationDelayData.AnimationDelay)); + var fld_raycast = AccessTools.Field(typeof(AnimationDelays), nameof(AnimationDelays.RayCast)); + + for (var i = 0; i < codes.Count; i++) + { + if (codes[i].LoadsField(fld_delayarr)) + { + for (int j = i + 1; j < codes.Count; j++) + { + if (codes[j].LoadsField(fld_raycast)) + { + bool flag = codes[i - 1].LoadsConstant(2f); + codes.RemoveRange(flag ? i - 1 : i, j - i + (flag ? 3 : 1)); + codes.InsertRange(flag ? i - 1 : i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemAction), nameof(ItemAction.Delay)) + }); + break; + } + } + break; + } + } + + return codes; + } + + //[HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPrefix] + //private bool Prefix_OnHoldingUpdate(ItemAction __instance, ItemActionData _actionData, out AnimationDelays __state) + //{ + // __state = AnimationDelayData.AnimationDelay[_actionData.invData.item.HoldType.Value]; + // if (!__instance.UseAnimation) + // return true; + // var modifiedData = __state; + // modifiedData.RayCast = __instance.Delay; + // AnimationDelayData.AnimationDelay[_actionData.invData.item.HoldType.Value] = modifiedData; + // return true; + //} + + //[HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPostfix] + //private void Postfix_OnHoldingUpdate(ItemAction __instance, ItemActionData _actionData, AnimationDelays __state) + //{ + // if (!__instance.UseAnimation) + // return; + // AnimationDelayData.AnimationDelay[_actionData.invData.item.HoldType.Value] = __state; + //} + + //[HarmonyPatch(nameof(ItemAction.IsActionRunning)), MethodTargetPrefix] + //private bool Prefix_IsActionRunning(ItemAction __instance, ItemActionData _actionData, out AnimationDelays __state) + //{ + // __state = AnimationDelayData.AnimationDelay[_actionData.invData.item.HoldType.Value]; + // if (!__instance.UseAnimation) + // return true; + // var modifiedData = __state; + // modifiedData.RayCast = __instance.Delay * .5f; + // AnimationDelayData.AnimationDelay[_actionData.invData.item.HoldType.Value] = modifiedData; + // return true; + //} + + //[HarmonyPatch(nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + //private void Postfix_IsActionRunning(ItemAction __instance, ItemActionData _actionData, AnimationDelays __state) + //{ + // if (!__instance.UseAnimation) + // return; + // AnimationDelayData.AnimationDelay[_actionData.invData.item.HoldType.Value] = __state; + //} + + //following are fix for item use time from menu entry + //when IsActionRunning is called from coroutine which is started by menu entry, + //as OnHoldingUpdate is not called every frame, the check might yield false before item actually gets consumed, thus returning the item + //so we call OnHoldingUpdate to properly consume the item + //vanilla method on the other hand, is forcing double delay in IsActionRunning + [HarmonyPatch(typeof(ItemActionEat), nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning_ItemActionEat(ItemActionEat __instance, ItemActionData _actionData/*, AnimationDelays __state*/, bool __result) + { + //Postfix_IsActionRunning(__instance, _actionData, __state); + if (!__result && ((ItemActionEat.MyInventoryData)_actionData).bEatingStarted) + { + __instance.OnHoldingUpdate(_actionData); + } + } + + [HarmonyPatch(typeof(ItemActionGainSkill), nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning_ItemActionGainSkill(ItemActionGainSkill __instance, ItemActionData _actionData/*, AnimationDelays __state*/, bool __result) + { + //Postfix_IsActionRunning(__instance, _actionData, __state); + if (!__result && ((ItemActionGainSkill.MyInventoryData)_actionData).bReadingStarted) + { + __instance.OnHoldingUpdate(_actionData); + } + } + + [HarmonyPatch(typeof(ItemActionLearnRecipe), nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning_ItemActionLearnRecipe(ItemActionLearnRecipe __instance, ItemActionData _actionData/*, AnimationDelays __state*/, bool __result) + { + //Postfix_IsActionRunning(__instance, _actionData, __state); + if (!__result && ((ItemActionLearnRecipe.MyInventoryData)_actionData).bReadingStarted) + { + __instance.OnHoldingUpdate(_actionData); + } + } + + [HarmonyPatch(typeof(ItemActionQuest), nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning_ItemActionQuest(ItemActionQuest __instance, ItemActionData _actionData/*, AnimationDelays __state*/, bool __result) + { + //Postfix_IsActionRunning(__instance, _actionData, __state); + if (!__result && ((ItemActionQuest.MyInventoryData)_actionData).bQuestAccept) + { + __instance.OnHoldingUpdate(_actionData); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleDisplayAsBuff.cs b/Scripts/Items/ModularActions/ActionModuleDisplayAsBuff.cs new file mode 100644 index 0000000..ac43cb3 --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleDisplayAsBuff.cs @@ -0,0 +1,78 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; + +public class DisplayAsBuffEntityUINotification : BuffEntityUINotification +{ + public ActionModuleDisplayAsBuff.DisplayValueType displayType = ActionModuleDisplayAsBuff.DisplayValueType.Meta; + public string displayData = string.Empty; + + public override float CurrentValue + { + get + { + EntityPlayerLocal player = GameManager.Instance.World.GetPrimaryPlayer(); + if (player == null) + return 0; + switch (displayType) + { + case ActionModuleDisplayAsBuff.DisplayValueType.Meta: + return player.inventory.holdingItemItemValue.Meta; + case ActionModuleDisplayAsBuff.DisplayValueType.MetaData: + return (float)player.inventory.holdingItemItemValue.GetMetadata(displayData); + default: + return 0; + } + } + } + + public override bool Visible => true; + + public override EnumEntityUINotificationDisplayMode DisplayMode => EnumEntityUINotificationDisplayMode.IconPlusCurrentValue; +} + +[TypeTarget(typeof(ItemActionRanged))] +public class ActionModuleDisplayAsBuff +{ + public enum DisplayValueType + { + Meta, + MetaData + } + + private DisplayAsBuffEntityUINotification notification; + private BuffClass buffClass; + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props) + { + notification = new DisplayAsBuffEntityUINotification(); + _props.Values.TryGetValue("DisplayType", out string str); + EnumUtils.TryParse(str, out notification.displayType, true); + _props.Values.TryGetValue("DisplayData", out notification.displayData); + _props.Values.TryGetValue("DisplayBuff", out str); + BuffClass buffClass = BuffManager.GetBuff(str); + BuffValue buff = new BuffValue(buffClass.Name, Vector3i.zero, -1, buffClass); + notification.SetBuff(buff); + } + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPostfix] + private void Postfix_StartHolding(ItemActionData _data) + { + EntityPlayerLocal player = _data.invData.holdingEntity as EntityPlayerLocal; + if (player != null && notification != null) + { + notification.SetStats(player.Stats); + player.Stats.NotificationAdded(notification); + } + } + + [HarmonyPatch(nameof(ItemAction.StopHolding)), MethodTargetPostfix] + private void Postfix_StopHolding(ItemActionData _data) + { + EntityPlayerLocal player = _data.invData.holdingEntity as EntityPlayerLocal; + if (player != null && notification != null) + { + player.Stats.NotificationRemoved(notification); + } + } +} diff --git a/Scripts/Items/ModularActions/ActionModuleDynamicGraze.cs b/Scripts/Items/ModularActions/ActionModuleDynamicGraze.cs new file mode 100644 index 0000000..2610c1e --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleDynamicGraze.cs @@ -0,0 +1,67 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; + +[TypeTarget(typeof(ItemActionDynamic))] +public class ActionModuleDynamicGraze +{ + private string dynamicSoundStart = null; + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPrefix] + private bool Prefix_ExecuteAction(ItemActionDynamic __instance, ItemActionData _actionData, bool _bReleased, out (bool executed, string originalSound) __state) + { + if (!_bReleased && !string.IsNullOrEmpty(dynamicSoundStart) && _actionData.invData.holdingEntity is EntityPlayerLocal player) + { + var targets = AnimationRiggingManager.GetRigTargetsFromPlayer(player); + if (targets && !targets.Destroyed && targets.IsAnimationSet) + { + __state = (true, __instance.soundStart); + __instance.soundStart = dynamicSoundStart; + return true; + } + } + __state = (false, null); + return true; + } + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPostfix] + private void Postfix_ExecuteAction(ItemActionDynamic __instance, (bool executed, string originalSound) __state) + { + if (__state.executed) + { + __instance.soundStart = __state.originalSound; + } + } + + [HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPrefix] + private bool Prefix_OnHoldingUpdate(ItemActionDynamic __instance, ItemActionData _actionData, out (bool executed, bool useGrazeCast) __state) + { + if (_actionData.invData.holdingEntity is EntityPlayerLocal player) + { + var targets = AnimationRiggingManager.GetRigTargetsFromPlayer(player); + if (targets && !targets.Destroyed && targets.ItemCurrent) + { + __state = (true, __instance.UseGrazingHits); + __instance.UseGrazingHits = false; + return true; + } + } + __state = (false, false); + return true; + } + + [HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPostfix] + private void Postfix_OnHoldingUpdate(ItemActionDynamic __instance, (bool executed, bool useGrazeCast) __state) + { + if (__state.executed) + { + __instance.UseGrazingHits = __state.useGrazeCast; + } + } + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props) + { + _props.ParseString("DynamicSoundStart", ref dynamicSoundStart); + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleDynamicMuzzleFlash.cs b/Scripts/Items/ModularActions/ActionModuleDynamicMuzzleFlash.cs new file mode 100644 index 0000000..9ea4506 --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleDynamicMuzzleFlash.cs @@ -0,0 +1,84 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.Utilities; + +[TypeTarget(typeof(ItemActionAttack)), ActionDataTarget(typeof(DynamicMuzzleFlashData))] +public class ActionModuleDynamicMuzzleFlash +{ + private struct State + { + public bool executed; + public string particlesMuzzleFire; + public string particlesMuzzleSmoke; + public string particlesMuzzleFireFpv; + public string particlesMuzzleSmokeFpv; + } + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationsChanged(ItemActionAttack __instance, ItemActionAttackData _data, DynamicMuzzleFlashData __customData) + { + __customData.particlesMuzzleFire = _data.invData.itemValue.GetPropertyOverrideForAction("Particles_muzzle_fire", __instance.particlesMuzzleFire, __instance.ActionIndex); + __customData.particlesMuzzleFireFpv = _data.invData.itemValue.GetPropertyOverrideForAction("Particles_muzzle_fire_fpv", __instance.particlesMuzzleFireFpv, __instance.ActionIndex); + __customData.particlesMuzzleSmoke = _data.invData.itemValue.GetPropertyOverrideForAction("Particles_muzzle_smoke", __instance.particlesMuzzleSmoke, __instance.ActionIndex); + __customData.particlesMuzzleSmokeFpv = _data.invData.itemValue.GetPropertyOverrideForAction("Particles_muzzle_smoke_fpv", __instance.particlesMuzzleSmokeFpv, __instance.ActionIndex); + if (!string.IsNullOrEmpty(__customData.particlesMuzzleFire) && !ParticleEffect.IsAvailable(__customData.particlesMuzzleFire)) + { + ParticleEffect.LoadAsset(__customData.particlesMuzzleFire); + } + if (!string.IsNullOrEmpty(__customData.particlesMuzzleFireFpv) && !ParticleEffect.IsAvailable(__customData.particlesMuzzleFireFpv)) + { + ParticleEffect.LoadAsset(__customData.particlesMuzzleFireFpv); + } + if (!string.IsNullOrEmpty(__customData.particlesMuzzleSmoke) && !ParticleEffect.IsAvailable(__customData.particlesMuzzleSmoke)) + { + ParticleEffect.LoadAsset(__customData.particlesMuzzleSmoke); + } + if (!string.IsNullOrEmpty(__customData.particlesMuzzleSmokeFpv) && !ParticleEffect.IsAvailable(__customData.particlesMuzzleSmokeFpv)) + { + ParticleEffect.LoadAsset(__customData.particlesMuzzleSmokeFpv); + } + } + + [HarmonyPatch(nameof(ItemAction.ItemActionEffects)), MethodTargetPrefix] + private bool Prefix_ItemActionEffects(ItemActionAttack __instance, DynamicMuzzleFlashData __customData, out State __state) + { + __state = new State() + { + executed = true, + particlesMuzzleFire = __instance.particlesMuzzleFire, + particlesMuzzleFireFpv = __instance.particlesMuzzleFireFpv, + particlesMuzzleSmoke = __instance.particlesMuzzleSmoke, + particlesMuzzleSmokeFpv = __instance.particlesMuzzleSmokeFpv + }; + __instance.particlesMuzzleFire = __customData.particlesMuzzleFire; + __instance.particlesMuzzleFireFpv = __customData .particlesMuzzleFireFpv; + __instance.particlesMuzzleSmoke = __customData.particlesMuzzleSmoke; + __instance.particlesMuzzleSmokeFpv = __customData.particlesMuzzleSmokeFpv; + return true; + } + + [HarmonyPatch(nameof(ItemAction.ItemActionEffects)), MethodTargetPostfix] + private void Postfix_ItemActionEffects(ItemActionAttack __instance, State __state) + { + if (__state.executed) + { + __instance.particlesMuzzleFire = __state.particlesMuzzleFire; + __instance.particlesMuzzleFireFpv = __state.particlesMuzzleFireFpv; + __instance.particlesMuzzleSmoke = __state.particlesMuzzleSmoke; + __instance.particlesMuzzleSmokeFpv = __state.particlesMuzzleSmokeFpv; + } + } + + public class DynamicMuzzleFlashData + { + public string particlesMuzzleFire; + public string particlesMuzzleFireFpv; + public string particlesMuzzleSmoke; + public string particlesMuzzleSmokeFpv; + + public DynamicMuzzleFlashData(ItemInventoryData _invData, int _indexOfAction, ActionModuleDynamicMuzzleFlash _module) + { + + } + } +} diff --git a/Scripts/Items/ModularActions/ActionModuleDynamicSensitivity.cs b/Scripts/Items/ModularActions/ActionModuleDynamicSensitivity.cs new file mode 100644 index 0000000..80b9adb --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleDynamicSensitivity.cs @@ -0,0 +1,93 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using UnityEngine; + +[TypeTarget(typeof(ItemActionZoom)), ActionDataTarget(typeof(DynamicSensitivityData))] +public class ActionModuleDynamicSensitivity +{ + [HarmonyPatch(nameof(ItemAction.AimingSet)), MethodTargetPostfix] + private void Postfix_AimingSet(ItemActionData _actionData, bool _isAiming, bool _wasAiming, DynamicSensitivityData __customData) + { + float originalSensitivity = GamePrefs.GetFloat(EnumGamePrefs.OptionsZoomSensitivity); + if (_isAiming) + { + PlayerMoveController.Instance.mouseZoomSensitivity = originalSensitivity / Mathf.Sqrt(__customData.ZoomRatio); + } + else + { + PlayerMoveController.Instance.mouseZoomSensitivity = originalSensitivity; + } + } + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationsChanged(ItemActionZoom __instance, ItemActionData _data, DynamicSensitivityData __customData) + { + if (_data is IModuleContainerFor variableZoomData) + { + __customData.variableZoomData = variableZoomData.Instance; + } + else + { + string str = __instance.Properties.GetString("ZoomRatio"); + if (string.IsNullOrEmpty(str)) + { + str = "1"; + } + __customData.ZoomRatio = StringParsers.ParseFloat(_data.invData.itemValue.GetPropertyOverride("ZoomRatio", str)); + } + + __customData.dsRangeOverride = StringParsers.ParseVector2(_data.invData.itemValue.GetPropertyOverride("DynamicSensitivityRange", "0,0")); + } + + [HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPostfix] + private void Postfix_OnHoldingUpdate(ItemActionData _actionData, DynamicSensitivityData __customData) + { + if (((ItemActionZoom.ItemActionDataZoom)_actionData).aimingValue) + { + float originalSensitivity = GamePrefs.GetFloat(EnumGamePrefs.OptionsZoomSensitivity); + if (__customData.activated) + { + PlayerMoveController.Instance.mouseZoomSensitivity = originalSensitivity / Mathf.Sqrt(__customData.ZoomRatio); + } + else + { + PlayerMoveController.Instance.mouseZoomSensitivity = originalSensitivity; + } + } + } + + public class DynamicSensitivityData + { + public ActionModuleVariableZoom.VariableZoomData variableZoomData = null; + private float zoomRatio = 1.0f; + public Vector2 dsRangeOverride = Vector2.zero; + public bool activated = false; + + public float ZoomRatio + { + get + { + if (variableZoomData != null) + { + if (dsRangeOverride.x > 0 && dsRangeOverride.y >= dsRangeOverride.x) + { + return Mathf.Lerp(dsRangeOverride.x, dsRangeOverride.y, Mathf.InverseLerp(variableZoomData.minScale, variableZoomData.maxScale, variableZoomData.curScale)); + } + if (!variableZoomData.forceFov) + { + return variableZoomData.curScale; + } + return 1f; + } + return zoomRatio; + } + set => zoomRatio = value; + } + + public DynamicSensitivityData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleDynamicSensitivity _module) + { + + } + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleErgoAffected.cs b/Scripts/Items/ModularActions/ActionModuleErgoAffected.cs new file mode 100644 index 0000000..7e64e0f --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleErgoAffected.cs @@ -0,0 +1,157 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System.Collections.Generic; +using System.Reflection.Emit; +using UniLinq; +using UnityEngine; +using static ActionModuleErgoAffected; + +[TypeTarget(typeof(ItemActionZoom)), ActionDataTarget(typeof(ErgoData))] +public class ActionModuleErgoAffected +{ + public static readonly int AimSpeedModifierHash = Animator.StringToHash("AimSpeedModifier"); + public float zoomInTimeBase; + public float aimSpeedModifierBase; + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationChanged(ItemActionData _data, ItemActionZoom __instance, ErgoData __customData) + { + zoomInTimeBase = 0.3f; + __instance.Properties.ParseFloat("ZoomInTimeBase", ref zoomInTimeBase); + aimSpeedModifierBase = 1f; + __instance.Properties.ParseFloat("AimSpeedModifierBase", ref aimSpeedModifierBase); + __customData.aimStartTime = float.MaxValue; + __customData.aimSet = false; + } + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPostfix] + private void Postfix_ExecuteAction(ItemActionData _actionData, ItemActionZoom __instance, bool _bReleased, ErgoData __customData) + { + EntityAlive holdingEntity = _actionData.invData.holdingEntity; + ItemActionData prevActionData = holdingEntity.MinEventContext.ItemActionData; + holdingEntity.MinEventContext.ItemActionData = _actionData.invData.actionData[MultiActionManager.GetActionIndexForEntity(holdingEntity)]; + __customData.curErgo = EffectManager.GetValue(CustomEnums.WeaponErgonomics, _actionData.invData.itemValue, 0, holdingEntity); + float aimSpeedModifier = __customData.ModifiedErgo; + Log.Out($"Ergo is {__customData.curErgo}, base aim modifier is {aimSpeedModifierBase}, aim speed is {aimSpeedModifier * aimSpeedModifierBase}"); + holdingEntity.emodel.avatarController.UpdateFloat(AimSpeedModifierHash, aimSpeedModifier * aimSpeedModifierBase, true); + holdingEntity.MinEventContext.ItemActionData = prevActionData; + if ((_actionData as ItemActionZoom.ItemActionDataZoom).aimingValue && !_bReleased) + { + __customData.aimStartTime = Time.time; + } + else if (!(_actionData as ItemActionZoom.ItemActionDataZoom).aimingValue) + { + __customData.aimStartTime = float.MaxValue; + } + __customData.aimSet = false; + } + + //[MethodTargetPostfix(nameof(ItemAction.OnHoldingUpdate))] + //private void Postfix_OnHoldingUpdate(ItemActionData _actionData, ErgoData __customData) + //{ + // if ((_actionData as ItemActionZoom.ItemActionDataZoom).aimingValue && Time.time - __customData.aimStartTime > zoomInTimeBase) + // { + // __customData.aimSet = true; + // } + // else + // { + // __customData.aimSet = false; + // } + //} + + public class ErgoData + { + public float aimStartTime; + public bool aimSet; + public ActionModuleErgoAffected module; + public float curErgo; + public float ModifiedErgo => Mathf.Lerp(0.2f, 1, curErgo); + + public ErgoData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleErgoAffected _module) + { + aimStartTime = float.MaxValue; + aimSet = false; + module = _module; + } + } +} + +[HarmonyPatch] +public static class ErgoPatches +{ + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.updateAccuracy))] + [HarmonyTranspiler] + private static IEnumerable Transpiler_ItemActionRanged_updateAccuracy(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + var mtd_lerp = AccessTools.Method(typeof(Mathf), nameof(Mathf.Lerp), new[] { typeof(float), typeof(float), typeof(float) }); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_lerp)) + { + codes.InsertRange(i, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Ldarg_2), + CodeInstruction.Call(typeof(ErgoPatches), nameof(CalcErgoModifier)), + }); + break; + } + } + + return codes; + } + + private static float CalcErgoModifier(float originalValue, ItemAction action, ItemActionData actionData, bool aiming) + { + ItemActionRanged.ItemActionDataRanged rangedData = actionData as ItemActionRanged.ItemActionDataRanged; + if (aiming && rangedData.invData.actionData[1] is IModuleContainerFor dataModule && !dataModule.Instance.aimSet && Time.time - dataModule.Instance.aimStartTime > 0) + { + ActionModuleErgoAffected.ErgoData ergoData = dataModule.Instance; + float baseAimTime = ergoData.module.zoomInTimeBase; + float baseAimMultiplier = ergoData.module.aimSpeedModifierBase; + baseAimTime /= baseAimMultiplier; + //float modifiedErgo = EffectManager.GetValue(CustomEnums.WeaponErgonomics, rangedData.invData.itemValue, 1f, rangedData.invData.holdingEntity); + float modifiedErgo = ergoData.ModifiedErgo; + float perc = (Time.time - ergoData.aimStartTime) * modifiedErgo / baseAimTime; + if (perc >= 1) + { + ergoData.aimSet = true; + perc = 1; + } + //Log.Out($"Time passed {Time.time - dataModule.Instance.aimStartTime} base time {baseAimTime} perc {perc}"); + return perc; + } + return originalValue; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.onHoldingEntityFired))] + [HarmonyPrefix] + private static bool Prefix_onHoldingEntityFired_ItemActionRanged(ItemActionData _actionData, out float __state) + { + __state = (_actionData as ItemActionRanged.ItemActionDataRanged).lastAccuracy; + return true; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.onHoldingEntityFired))] + [HarmonyPostfix] + private static void Postfix_onHoldingEntityFired_ItemActionRanged(ItemActionData _actionData, float __state) + { + ItemActionRanged.ItemActionDataRanged rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + if (rangedData.invData.holdingEntity.AimingGun && rangedData.invData.actionData[1] is IModuleContainerFor dataModule) + { + float aimMultiplier = EffectManager.GetValue(PassiveEffects.SpreadMultiplierAiming, rangedData.invData.itemValue, .1f, rangedData.invData.holdingEntity); + rangedData.lastAccuracy = Mathf.Lerp(__state, rangedData.lastAccuracy, aimMultiplier); + ActionModuleErgoAffected.ErgoData ergoData = dataModule.Instance; + if (Time.time > ergoData.aimStartTime) + { + ergoData.aimSet = false; + ergoData.aimStartTime = Time.time; + } + } + } +} diff --git a/Scripts/Items/ModularActions/ActionModuleFireModeSelector.cs b/Scripts/Items/ModularActions/ActionModuleFireModeSelector.cs new file mode 100644 index 0000000..af47bdb --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleFireModeSelector.cs @@ -0,0 +1,336 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +[TypeTarget(typeof(ItemActionRanged)), ActionDataTarget(typeof(FireModeData))] +public class ActionModuleFireModeSelector +{ + public struct FireMode + { + public byte burstCount; + public bool isFullAuto; + } + public string fireModeSwitchingSound = null; + private List modeCache = new List(); + private List nameCache = new List(); + public static string[] FireModeNames = new[] + { + "FireMode", + "FireMode1", + "FireMode2", + "FireMode3", + "FireMode4", + }; + public static int[] FireModeParamHashes = new[] + { + Animator.StringToHash("FireMode"), + Animator.StringToHash("FireMode1"), + Animator.StringToHash("FireMode2"), + Animator.StringToHash("FireMode3"), + Animator.StringToHash("FireMode4"), + }; + public static int[] FireModeSwitchParamHashes = new[] + { + Animator.StringToHash("FireModeChanged"), + Animator.StringToHash("FireModeChanged1"), + Animator.StringToHash("FireModeChanged2"), + Animator.StringToHash("FireModeChanged3"), + Animator.StringToHash("FireModeChanged4"), + }; + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationChanged(ItemActionData _data, FireModeData __customData, ItemActionRanged __instance) + { + __instance.Properties.ParseString("FireModeSwitchingSound", ref fireModeSwitchingSound); + int actionIndex = _data.indexInEntityOfAction; + for (int i = 0; i < 99; i++) + { + if (!__instance.Properties.Contains($"FireMode{i}.BurstCount")) + { + break; + } + string burstCount = 1.ToString(); + __instance.Properties.ParseString($"FireMode{i}.BurstCount", ref burstCount); + string isFullAuto = false.ToString(); + __instance.Properties.ParseString($"FireMode{i}.IsFullAuto", ref isFullAuto); + string modeName = null; + __instance.Properties.ParseString($"FireMode{i}.ModeName", ref modeName); + modeCache.Add(new FireMode + { + burstCount = byte.Parse(_data.invData.itemValue.GetPropertyOverrideForAction($"FireMode{i}.BurstCount", burstCount, actionIndex)), + isFullAuto = bool.Parse(_data.invData.itemValue.GetPropertyOverrideForAction($"FireMode{i}.IsFullAuto", isFullAuto, actionIndex)) + }); + nameCache.Add(_data.invData.itemValue.GetPropertyOverrideForAction($"FireMode{i}.ModeName", modeName, actionIndex)); + } + for (int i = 0; i < 99; i++) + { + string burstCount = _data.invData.itemValue.GetPropertyOverrideForAction($"FireModePlus{i}.BurstCount", null, actionIndex); + if (burstCount == null) + { + break; + } + modeCache.Add(new FireMode + { + burstCount = byte.Parse(_data.invData.itemValue.GetPropertyOverrideForAction($"FireModePlus{i}.BurstCount", burstCount, actionIndex)), + isFullAuto = bool.Parse(_data.invData.itemValue.GetPropertyOverrideForAction($"FireModePlus{i}.IsFullAuto", "false", actionIndex)) + }); + nameCache.Add(_data.invData.itemValue.GetPropertyOverrideForAction($"FireModePlus{i}.ModeName", null, actionIndex)); + } + __customData.fireModes = modeCache.ToArray(); + modeCache.Clear(); + __customData.modeNames = nameCache.ToArray(); + nameCache.Clear(); + if (_data.invData.itemValue.GetMetadata(FireModeNames[actionIndex]) is int mode) + { + __customData.currentFireMode = (byte)mode; + } + if (__customData.currentFireMode < 0 || __customData.currentFireMode >= __customData.fireModes.Length) + { + __customData.currentFireMode = 0; + } + if (__customData.delayFiringCo != null) + { + ThreadManager.StopCoroutine(__customData.delayFiringCo); + __customData.delayFiringCo = null; + } + __customData.isRequestedByCoroutine = false; + } + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPostfix] + private void Postfix_StartHolding(ItemActionData _data, FireModeData __customData) + { + __customData.SetFireMode(_data, __customData.currentFireMode); + } + + [HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPostfix] + private static void Postfix_OnHoldingUpdate(ItemActionData _actionData, FireModeData __customData) + { + __customData.UpdateDelay(_actionData); + __customData.inputReleased = true; + } + + [HarmonyPatch(nameof(ItemAction.StopHolding)), MethodTargetPostfix] + private static void Postfix_StopHolding(FireModeData __customData) + { + if (__customData.delayFiringCo != null) + { + ThreadManager.StopCoroutine(__customData.delayFiringCo); + __customData.delayFiringCo = null; + } + __customData.isRequestedByCoroutine = false; + __customData.inputReleased = true; + } + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPrefix] + private bool Prefix_ExecuteAction(ItemActionData _actionData, ItemActionRanged __instance, FireModeData __customData, bool _bReleased) + { + if (__customData.isRequestedByCoroutine) + { + return true; + } + __customData.inputReleased = _bReleased; + if (__customData.delayFiringCo == null) + { + if (_bReleased || _actionData.invData.itemValue.Meta == 0 || _actionData.invData.itemValue.PercentUsesLeft <= 0) + { + return true; + } + FireMode curFireMode = __customData.fireModes[__customData.currentFireMode]; + if (curFireMode.burstCount == 1) + { + return true; + } + var rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + if (__instance.GetBurstCount(_actionData) > rangedData.curBurstCount) + { + __customData.StartFiring(__instance, _actionData); + } + } + return false; + } + + [HarmonyPatch(nameof(ItemActionRanged.GetBurstCount)), MethodTargetPostfix] + private void Postfix_GetBurstCount(FireModeData __customData, ref int __result) + { + FireMode fireMode = __customData.fireModes[__customData.currentFireMode]; + __result = fireMode.isFullAuto ? 999 : fireMode.burstCount; + } + + [HarmonyPatch(nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning(FireModeData __customData, ref bool __result) + { + __result |= __customData.delayFiringCo != null; + } + + public class FireModeData + { + public string switchSound; + public FireMode[] fireModes; + public string[] modeNames; + public byte currentFireMode; + public Coroutine delayFiringCo; + public bool isRequestedByCoroutine; + public float shotDelay; + public float burstDelay; + public bool inputReleased; + + public FireModeData(ItemInventoryData invData, int actionIndex, ActionModuleFireModeSelector module) + { + + } + + public void CycleFireMode(ItemActionData _data) + { + SetFireMode(_data, (byte)((currentFireMode + 1) % fireModes.Length)); + } + + public void SetFireMode(ItemActionData _data, byte _fireMode) + { + if (currentFireMode != _fireMode) + { + currentFireMode = _fireMode; + FireMode curFireMode = fireModes[currentFireMode]; + if (!string.IsNullOrEmpty(switchSound)) + { + _data.invData.holdingEntity.PlayOneShot(switchSound); + } + _data.invData.holdingEntity.emodel.avatarController.TriggerEvent(FireModeSwitchParamHashes[_data.indexInEntityOfAction]); + } + if (!string.IsNullOrEmpty(modeNames[_fireMode])) + { + GameManager.ShowTooltip(_data.invData.holdingEntity as EntityPlayerLocal, modeNames[_fireMode], true); + } + else + { + GameManager.ShowTooltip(_data.invData.holdingEntity as EntityPlayerLocal, "ttCurrentFiringMode", _fireMode.ToString(), null, null, true); + } + //GameManager.ShowTooltip(_data.invData.holdingEntity as EntityPlayerLocal, "ttCurrentFiringMode", string.IsNullOrEmpty(modeNames[_fireMode]) ? _fireMode.ToString() : Localization.Get(modeNames[_fireMode]), null, null, true); + _data.invData.holdingEntity.FireEvent(CustomEnums.onSelfBurstModeChanged); + UpdateDelay(_data); + + ItemValue itemValue = _data.invData.itemValue; + if (itemValue != null) + { + if (itemValue.Metadata == null) + { + itemValue.Metadata = new Dictionary(); + } + + if (!itemValue.Metadata.TryGetValue(ActionModuleFireModeSelector.FireModeNames[_data.indexInEntityOfAction], out var metadata) || !metadata.SetValue((int)_fireMode)) + { + itemValue.Metadata[ActionModuleFireModeSelector.FireModeNames[_data.indexInEntityOfAction]] = new TypedMetadataValue((int)_fireMode, TypedMetadataValue.TypeTag.Integer); + } + _data.invData.holdingEntity.inventory.CallOnToolbeltChangedInternal(); + } + } + + public void UpdateDelay(ItemActionData _data) + { + FireMode curFireMode = fireModes[currentFireMode]; + if (curFireMode.burstCount == 1) + { + return; + } + float burstInterval = EffectManager.GetValue(CustomEnums.BurstShotInterval, _data.invData.itemValue, -1, _data.invData.holdingEntity); + var rangedData = _data as ItemActionRanged.ItemActionDataRanged; + if (burstInterval > 0 && rangedData.Delay > burstInterval) + { + shotDelay = burstInterval; + burstDelay = (rangedData.Delay - burstInterval) * curFireMode.burstCount; + } + else + { + shotDelay = rangedData.Delay; + burstDelay = 0; + } + } + + public void StartFiring(ItemActionRanged _instance, ItemActionData _data) + { + UpdateDelay(_data); + if (delayFiringCo != null) + { + ThreadManager.StopCoroutine(delayFiringCo); + } + ((ItemActionRanged.ItemActionDataRanged)_data).bPressed = true; + ((ItemActionRanged.ItemActionDataRanged)_data).bReleased = false; + + delayFiringCo = ThreadManager.StartCoroutine(DelayFiring(_instance, _data)); + } + + private IEnumerator DelayFiring(ItemActionRanged _instance, ItemActionData _data) + { + FireMode curFireMode = fireModes[currentFireMode]; + var rangedData = _data as ItemActionRanged.ItemActionDataRanged; + byte curBurstCount = rangedData.curBurstCount; + for (int i = 0; i < curFireMode.burstCount; i++) + { + isRequestedByCoroutine = true; + rangedData.bPressed = true; + rangedData.bReleased = false; + rangedData.m_LastShotTime = 0; + _instance.ExecuteAction(_data, false); + rangedData.curBurstCount = (byte)(curBurstCount + i + 1); + isRequestedByCoroutine = false; + if (rangedData.invData.itemValue.Meta <= 0 && !_instance.HasInfiniteAmmo(_data)) + { + goto cleanup; + } + yield return new WaitForSeconds(shotDelay); + } + yield return new WaitForSeconds(burstDelay); + + cleanup: + delayFiringCo = null; + if (inputReleased) + { + _instance.ExecuteAction(_data, true); + } + } + } +} + +[HarmonyPatch] +public static class FireModePatches +{ + [HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))] + [HarmonyPrefix] + private static bool Prefix_Update_PlayerMoveController(PlayerMoveController __instance) + { + if (DroneManager.Debug_LocalControl || !__instance.gameManager.gameStateManager.IsGameStarted() || GameStats.GetInt(EnumGameStats.GameState) != 1) + return true; + + bool isUIOpen = __instance.windowManager.IsCursorWindowOpen() || __instance.windowManager.IsInputActive() || __instance.windowManager.IsModalWindowOpen(); + + UpdateLocalInput(__instance.entityPlayerLocal, isUIOpen); + + return true; + } + + private static void UpdateLocalInput(EntityPlayerLocal _player, bool _isUIOpen) + { + if (_isUIOpen || _player.emodel.IsRagdollActive || _player.IsDead() || _player.AttachedToEntity != null) + { + return; + } + + if (PlayerActionKFLib.Instance.Enabled && PlayerActionKFLib.Instance.ToggleFireMode.WasPressed) + { + if (_player.inventory.IsHoldingItemActionRunning()) + { + return; + } + + var actionData = _player.inventory.holdingItemData.actionData[MultiActionManager.GetActionIndexForEntity(_player)]; + if (actionData is IModuleContainerFor fireModeData) + { + fireModeData.Instance.CycleFireMode(actionData); + } + } + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleHoldOpen.cs b/Scripts/Items/ModularActions/ActionModuleHoldOpen.cs new file mode 100644 index 0000000..75a1c46 --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleHoldOpen.cs @@ -0,0 +1,85 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using System.Collections; +using UnityEngine; + +[TypeTarget(typeof(ItemActionRanged))] +public class ActionModuleHoldOpen +{ + private const string emptyAnimatorBool = "empty"; + private int emptyAnimatorBoolHash; + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props, ItemActionRanged __instance) + { + int metaIndex = __instance.ActionIndex; + if (_props.Values.TryGetValue("ShareMetaWith", out string str) && int.TryParse(str, out metaIndex)) + { + + } + if (metaIndex > 0) + { + emptyAnimatorBoolHash = Animator.StringToHash(emptyAnimatorBool + __instance.ActionIndex); + } + else + { + emptyAnimatorBoolHash = Animator.StringToHash(emptyAnimatorBool); + } + } + + [HarmonyPatch(nameof(ItemActionRanged.getUserData)), MethodTargetPostfix] + public void Postfix_getUserData(ItemActionData _actionData, ref int __result) + { + __result |= (_actionData.invData.itemValue.Meta <= 0 ? 1 : 0); + } + + [HarmonyPatch(nameof(ItemAction.ItemActionEffects)), MethodTargetPostfix] + public void Postfix_ItemActionEffects(ItemActionData _actionData, int _firingState, int _userData) + { + if (_firingState != (int)ItemActionFiringState.Off && (_userData & 1) > 0) + _actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(emptyAnimatorBoolHash, true, false); + } + + [HarmonyPatch(nameof(ItemActionRanged.ReloadGun)), MethodTargetPostfix] + public void Postfix_ReloadGun(ItemActionData _actionData) + { + //delay 2 frames before reloading, since the animation is likely to be triggered the next frame this is called + ThreadManager.StartCoroutine(DelaySetEmpty(_actionData, false, 2)); + } + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPrefix] + public bool Prefix_StartHolding(ItemActionData _data) + { + //delay 1 frame before equipping weapon + if (_data.invData.itemValue.Meta <= 0) + ThreadManager.StartCoroutine(DelaySetEmpty(_data, true, 2)); + return true; + } + + [HarmonyPatch(nameof(ItemActionRanged.ConsumeAmmo)), MethodTargetPostfix] + public void Postfix_ConsumeAmmo(ItemActionData _actionData) + { + if (_actionData.invData.itemValue.Meta == 0) + _actionData.invData.holdingEntity.FireEvent(CustomEnums.onSelfMagzineDeplete, true); + } + + [HarmonyPatch(nameof(ItemAction.SwapAmmoType)), MethodTargetPrefix] + public bool Prefix_SwapAmmoType(EntityAlive _entity) + { + _entity.emodel.avatarController.UpdateBool(emptyAnimatorBoolHash, true, false); + return true; + } + + private IEnumerator DelaySetEmpty(ItemActionData _actionData, bool empty, int delay) + { + for (int i = 0; i < delay; i++) + { + yield return null; + } + if (_actionData.invData.holdingEntity.inventory.holdingItemIdx == _actionData.invData.slotIdx) + { + _actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(emptyAnimatorBoolHash, empty, false); + } + yield break; + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleInspectable.cs b/Scripts/Items/ModularActions/ActionModuleInspectable.cs new file mode 100644 index 0000000..b11d2d0 --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleInspectable.cs @@ -0,0 +1,24 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; + +[TypeTarget(typeof(ItemAction))] +public class ActionModuleInspectable +{ + public bool allowEmptyInspect; + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props) + { + allowEmptyInspect = _props.GetBool("allowEmptyInspect"); + } + + [HarmonyPatch(typeof(ItemActionDynamic), nameof(ItemAction.CancelAction)), MethodTargetPostfix] + private void Postfix_CancelAction_ItemActionDynamic(ItemActionDynamic.ItemActionDynamicData _actionData) + { + var entity = _actionData.invData.holdingEntity; + if (!entity.MovementRunning && _actionData != null && !entity.inventory.holdingItem.IsActionRunning(entity.inventory.holdingItemData)) + { + entity.emodel.avatarController._setTrigger("weaponInspect", false); + } + } +} diff --git a/Scripts/Items/ModularActions/ActionModuleInterruptReload.cs b/Scripts/Items/ModularActions/ActionModuleInterruptReload.cs new file mode 100644 index 0000000..fd836fe --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleInterruptReload.cs @@ -0,0 +1,225 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using UnityEngine; + +[TypeTarget(typeof(ItemActionRanged)), ActionDataTarget(typeof(InterruptData))] +public class ActionModuleInterruptReload +{ + public float holdBeforeCancel = 0.06f; + public string firingStateName = ""; + public bool instantFiringCancel = false; + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPrefix] + private bool Prefix_StartHolding(InterruptData __customData) + { + __customData.Reset(); + return true; + } + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props) + { + firingStateName = _props.GetString("FiringStateFullName"); + instantFiringCancel = _props.GetBool("InstantFiringCancel"); + } + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationsChanged(ItemActionData _data, InterruptData __customData) + { + var invData = _data.invData; + __customData.itemAnimator = AnimationGraphBuilder.DummyWrapper; + __customData.eventBridge = null; + if (invData.model && invData.model.TryGetComponent(out var targets) && !targets.Destroyed && targets.IsAnimationSet) + { + __customData.itemAnimator = targets.GraphBuilder.WeaponWrapper; + if (__customData.itemAnimator.IsValid) + { + __customData.eventBridge = targets.ItemAnimator.GetComponent(); + } + } + } + + private struct State + { + public bool executed; + public bool isReloading; + public bool isWeaponReloading; + public float lastShotTime; + } + + [HarmonyPatch(nameof(ItemAction.IsActionRunning)), MethodTargetPostfix] + private void Postfix_IsActionRunning(ref bool __result, InterruptData __customData) + { + __result &= !__customData.instantFiringRequested; + } + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPrefix] + private bool Prefix_ExecuteAction(ItemActionData _actionData, bool _bReleased, InterruptData __customData, out State __state) + { + __state = default; + if (!_bReleased && __customData.isInterruptRequested && __customData.instantFiringRequested) + { + if (_actionData.invData.itemValue.Meta > 0) + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"instant firing cancel prefix!"); + ItemActionRanged.ItemActionDataRanged rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + __state.executed = true; + __state.isReloading = rangedData.isReloading; + __state.isWeaponReloading = rangedData.isWeaponReloading; + __state.lastShotTime = rangedData.m_LastShotTime; + rangedData.isReloading = false; + rangedData.isWeaponReloading = false; + } + else + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"not fired! meta is 0"); + __customData.isInterruptRequested = false; + __customData.instantFiringRequested = false; + return false; + } + } + return true; + } + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPostfix] + private void Postfix_ExecuteAction(ItemActionData _actionData, InterruptData __customData, State __state) + { + if (__state.executed) + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"instant firing cancel postfix!"); + ItemActionRanged.ItemActionDataRanged rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + rangedData.isReloading = __state.isReloading; + rangedData.isWeaponReloading = __state.isWeaponReloading; + if (__customData.itemAnimator.IsValid && __customData.eventBridge) + { + if (rangedData.m_LastShotTime > __state.lastShotTime && rangedData.m_LastShotTime < Time.time + 1f) + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"executed!"); + __customData.eventBridge.OnReloadEnd(); + __customData.itemAnimator.Play(firingStateName, -1, 0f); + } + else + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"not fired! last shot time {__state.lastShotTime} ranged data shot time {rangedData.m_LastShotTime} cur time {Time.time}"); + __customData.isInterruptRequested = false; + __customData.instantFiringRequested = false; + } + } + } + } + + [HarmonyPatch(nameof(ItemAction.ItemActionEffects)), MethodTargetPrefix] + private bool Prefix_ItemActionEffects(ItemActionData _actionData, int _firingState, InterruptData __customData) + { + var rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + if (_firingState != 0 && (rangedData.isReloading || rangedData.isWeaponReloading) && !(rangedData.invData.holdingEntity is EntityPlayerLocal) && __customData.eventBridge) + { + __customData.eventBridge.OnReloadEnd(); + __customData.itemAnimator.Play(firingStateName, -1, 0f); + } + return true; + } + + public bool IsRequestPossible(InterruptData interruptData) + { + return interruptData.eventBridge && interruptData.itemAnimator.IsValid; + } + + public class InterruptData + { + public bool isInterruptRequested; + public float holdStartTime = -1f; + public bool instantFiringRequested = false; + public AnimationReloadEvents eventBridge; + public IAnimatorWrapper itemAnimator; + + public InterruptData(ItemInventoryData invData, int actionIndex, ActionModuleInterruptReload module) + { + //if (invData.model && invData.model.TryGetComponent(out var targets) && !targets.Destroyed) + //{ + // itemAnimator = targets.ItemAnimator; + // if (itemAnimator) + // { + // eventBridge = itemAnimator.GetComponent(); + // } + //} + } + + public void Reset() + { + isInterruptRequested = false; + holdStartTime = -1f; + instantFiringRequested = false; + } + } +} + +[HarmonyPatch] +internal static class ReloadInterruptionPatches +{ + //interrupt reload with firing + [HarmonyPatch(typeof(ItemClass), nameof(ItemClass.ExecuteAction))] + [HarmonyPrefix] + private static bool Prefix_ExecuteAction_ItemClass(ItemClass __instance, int _actionIdx, ItemInventoryData _data, bool _bReleased, PlayerActionsLocal _playerActions) + { + ItemAction curAction = __instance.Actions[_actionIdx]; + if (curAction is ItemActionRanged || curAction is ItemActionZoom) + { + int curActionIndex = MultiActionManager.GetActionIndexForEntity(_data.holdingEntity); + var rangedAction = __instance.Actions[curActionIndex] as ItemActionRanged; + var rangedData = _data.actionData[curActionIndex] as ItemActionRanged.ItemActionDataRanged; + if (rangedData != null && rangedData is IModuleContainerFor dataModule && rangedAction is IModuleContainerFor actionModule) + { + if (!_bReleased && _playerActions != null && actionModule.Instance.IsRequestPossible(dataModule.Instance) && ((_playerActions.Primary.IsPressed && _actionIdx == curActionIndex && _data.itemValue.Meta > 0) || (_playerActions.Secondary.IsPressed && curAction is ItemActionZoom)) && (rangedData.isReloading || rangedData.isWeaponReloading) && !dataModule.Instance.isInterruptRequested) + { + if (dataModule.Instance.holdStartTime < 0) + { + dataModule.Instance.holdStartTime = Time.time; + return false; + } + if (Time.time - dataModule.Instance.holdStartTime >= actionModule.Instance.holdBeforeCancel) + { + if (!rangedAction.reloadCancelled(rangedData)) + { + rangedAction.CancelReload(rangedData); + } + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"interrupt requested!"); + dataModule.Instance.isInterruptRequested = true; + if (actionModule.Instance.instantFiringCancel && curAction is ItemActionRanged) + { + if (ConsoleCmdReloadLog.LogInfo) + Log.Out($"instant firing cancel!"); + dataModule.Instance.instantFiringRequested = true; + return true; + } + } + return false; + } + if (_bReleased) + { + dataModule.Instance.Reset(); + } + } + } + return true; + } + + [HarmonyPatch(typeof(ItemAction), nameof(ItemAction.CancelReload))] + [HarmonyPrefix] + private static bool Prefix_CancelReload_ItemAction(ItemActionData _actionData) + { + if (_actionData?.invData?.holdingEntity is EntityPlayerLocal && AnimationRiggingManager.IsHoldingRiggedWeapon(_actionData.invData.holdingEntity as EntityPlayerLocal)) + { + return false; + } + return true; + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleInvariableRPM.cs b/Scripts/Items/ModularActions/ActionModuleInvariableRPM.cs new file mode 100644 index 0000000..0dbf9f8 --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleInvariableRPM.cs @@ -0,0 +1,60 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System.Collections.Generic; +using System.Reflection.Emit; +using UniLinq; + +[TypeTarget(typeof(ItemActionRanged))] +public class ActionModuleInvariableRPM +{ + //added as a transpiler so that it's applied before all post processing + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.OnHoldingUpdate)), MethodTargetTranspiler] + private static IEnumerable Transpiler_OnHoldingUpdate_ItemActionRanged(IEnumerable instructions) + { + var codes = instructions.ToList(); + + var mtd_getvalue = AccessTools.Method(typeof(EffectManager), nameof(EffectManager.GetValue)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].Calls(mtd_getvalue)) + { + int start = -1; + for (int j = i; j >= 0; j--) + { + if (codes[j].opcode == OpCodes.Stloc_0) + { + start = j + 2; + break; + } + } + if (start >= 0) + { + codes.InsertRange(i + 2, new[] + { + new CodeInstruction(OpCodes.Ldarg_0), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.Call(typeof(ActionModuleInvariableRPM), nameof(CalcFixedRPM)) + }); + codes.RemoveRange(start, i - start + 2); + //Log.Out("Invariable RPM Patch applied!"); + } + break; + } + } + + return codes; + } + + private static float CalcFixedRPM(ItemActionRanged rangedAction, ItemActionRanged.ItemActionDataRanged rangedData) + { + float rpm = 60f / rangedData.OriginalDelay; + float perc = 1f; + var tags = rangedData.invData.item.ItemTags; + MultiActionManager.ModifyItemTags(rangedData.invData.itemValue, rangedData, ref tags); + rangedData.invData.item.Effects.ModifyValue(rangedData.invData.holdingEntity, PassiveEffects.RoundsPerMinute, ref rpm, ref perc, rangedData.invData.itemValue.Quality, tags); + //Log.Out($"fixed RPM {res}"); + return 60f / (rpm * perc); + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleLocalPassiveCache.cs b/Scripts/Items/ModularActions/ActionModuleLocalPassiveCache.cs new file mode 100644 index 0000000..8c5ec9e --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleLocalPassiveCache.cs @@ -0,0 +1,105 @@ +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System; +using System.Collections; +using System.Collections.Generic; + +[TypeTarget(typeof(ItemAction)), ActionDataTarget(typeof(LocalPassiveCacheData))] +public class ActionModuleLocalPassiveCache +{ + //public int[] nameHashes; + + //[MethodTargetPostfix(nameof(ItemAction.ReadFrom))] + //private void Postfix_ReadFrom(DynamicProperties _props) + //{ + // string str = _props.Values["CachePassives"]; + // if (!string.IsNullOrEmpty(str)) + // { + // nameHashes = Array.ConvertAll(str.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), s => s.GetHashCode()); + // } + //} + + //[MethodTargetPrefix(nameof(ItemAction.StartHolding))] + //private bool Prefix_StartHolding(ItemActionData _data, LocalPassiveCacheData __customData) + //{ + // if (nameHashes != null) + // { + // for (int i = 0; i < nameHashes.Length; i++) + // { + // __customData.passives[i] = EffectManager.GetValue(nameHashes[i], _data.invData.itemValue, 0, _data.invData.holdingEntity); + // __customData.markedForCache[i] = false; + // } + // } + // return true; + //} + + //[MethodTargetPrefix(nameof(ItemAction.OnHoldingUpdate))] + //private bool Prefix_OnHoldingUpdate(ItemActionData _actionData, LocalPassiveCacheData __customData) + //{ + // if (!_actionData.invData.holdingEntity.isEntityRemote && nameHashes != null) + // { + // for (int i = 0; i < nameHashes.Length; i++) + // { + // if (__customData.markedForCache[i]) + // { + // __customData.cache[i] = EffectManager.GetValue(nameHashes[i], _actionData.invData.itemValue, 0, _actionData.invData.holdingEntity); + // __customData.markedForCache[i] = false; + // } + // } + // } + + // return true; + //} + + public class LocalPassiveCacheData : IEnumerable + { + //public float[] cache; + //public bool[] markedForCache; + //public ActionModuleLocalPassiveCache _cacheModule; + public ItemInventoryData invData; + private Dictionary dict_hash_value = new Dictionary(); + private Dictionary dict_hash_name = new Dictionary(); + + public LocalPassiveCacheData(ItemInventoryData _invData, int _indexOfAction, ActionModuleLocalPassiveCache _cacheModule) + { + //this._cacheModule = _cacheModule; + this.invData = _invData; + //if (_cacheModule.nameHashes != null) + //{ + // cache = new float[_cacheModule.nameHashes.Length]; + // //markedForCache = new bool[_cacheModule.nameHashes.Length]; + //} + } + + public void CachePassive(PassiveEffects target, int targetHash, string targetStr, FastTags tags) + { + if (invData.holdingEntity.isEntityRemote) + return; + if (!dict_hash_name.ContainsKey(targetHash)) + dict_hash_name[targetHash] = targetStr; + + dict_hash_value[targetHash] = EffectManager.GetValue(target, invData.itemValue, 0, invData.holdingEntity, null, tags); + //markedForCache[index] = true; + } + + public float GetCachedValue(int targetHash) + { + return dict_hash_value.TryGetValue(targetHash, out float res) ? res : 0; + } + + public string GetCachedName(int targetHash) + { + return dict_hash_name.TryGetValue(targetHash, out string res) ? res : string.Empty; + } + + public IEnumerator GetEnumerator() + { + return dict_hash_value.Keys.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + } +} diff --git a/Scripts/Items/ModularActions/ActionModuleMetaConsumer.cs b/Scripts/Items/ModularActions/ActionModuleMetaConsumer.cs new file mode 100644 index 0000000..d656fef --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleMetaConsumer.cs @@ -0,0 +1,178 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using System; +using System.Collections.Generic; +using System.Reflection.Emit; +using UniLinq; + +[TypeTarget(typeof(ItemActionRanged))] +public class ActionModuleMetaConsumer +{ + public string[] consumeDatas; + public FastTags[] consumeTags; + private float[] consumeStocks; + private float[] consumeValues; + private static FastTags TagsConsumption = FastTags.Parse("ConsumptionValue"); + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props, ItemAction __instance) + { + string consumeData = string.Empty; + _props.Values.TryGetValue("ConsumeData", out consumeData); + _props.Values.TryGetValue("ConsumeTags", out string tags); + FastTags commonTags = string.IsNullOrEmpty(tags) ? FastTags.none : FastTags.Parse(tags); + if (string.IsNullOrEmpty(consumeData)) + { + Log.Error($"No consume data found on item {__instance.item.Name} action {__instance.ActionIndex}"); + return; + } + + consumeDatas = consumeData.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray(); + consumeTags = consumeDatas.Select(s => FastTags.Parse(s) | commonTags | TagsConsumption).ToArray(); + consumeStocks = new float[consumeDatas.Length]; + consumeValues = new float[consumeDatas.Length]; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.ExecuteAction)), MethodTargetTranspiler] + private static IEnumerable Transpiler_ItemActionRanged_ExecuteAction(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + var fld_started = AccessTools.Field(typeof(ItemActionRanged.ItemActionDataRanged), nameof(ItemActionRanged.ItemActionDataRanged.burstShotStarted)); + var fld_infinite = AccessTools.Field(typeof(ItemActionAttack), nameof(ItemActionAttack.InfiniteAmmo)); + var mtd_consume = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.ConsumeAmmo)); + var lbd_module = generator.DeclareLocal(typeof(ActionModuleMetaConsumer)); + var prop_instance = AccessTools.PropertyGetter(typeof(IModuleContainerFor), nameof(IModuleContainerFor.Instance)); + var prop_itemvalue = AccessTools.PropertyGetter(typeof(ItemInventoryData), nameof(ItemInventoryData.itemValue)); + + for (int i = 0; i < codes.Count; i++) + { + if (codes[i].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 6) + { + codes.InsertRange(i - 4, new[] + { + new CodeInstruction(OpCodes.Ldarg_0).WithLabels(codes[i - 4].ExtractLabels()), + new CodeInstruction(OpCodes.Castclass, typeof(IModuleContainerFor)), + new CodeInstruction(OpCodes.Callvirt, prop_instance), + new CodeInstruction(OpCodes.Stloc_S, lbd_module), + }); + i += 4; + } + else if (codes[i].StoresField(fld_started) && codes[i - 1].LoadsConstant(1)) + { + var lbl = generator.DefineLabel(); + var original = codes[i - 2]; + codes.InsertRange(i - 2, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_module).WithLabels(original.ExtractLabels()), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)), + new CodeInstruction(OpCodes.Callvirt, prop_itemvalue), + new CodeInstruction(OpCodes.Ldloc_S, 6), + new CodeInstruction(OpCodes.Ldarg_0), + CodeInstruction.LoadField(typeof(ItemActionAttack), nameof(ItemActionAttack.soundEmpty)), + CodeInstruction.Call(typeof(ActionModuleMetaConsumer), nameof(CheckAndCacheMetaData)), + new CodeInstruction(OpCodes.Brtrue_S, lbl), + new CodeInstruction(OpCodes.Ret) + }); + original.WithLabels(lbl); + i += 10; + } + else if (codes[i].Calls(mtd_consume)) + { + var lbl = generator.DefineLabel(); + for (int j = i - 1; j >= 0; j--) + { + if (codes[j].LoadsField(fld_infinite) && codes[j + 1].Branches(out _)) + { + codes[j + 1].operand = lbl; + break; + } + } + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_module).WithLabels(lbl), + new CodeInstruction(OpCodes.Ldloc_0), + CodeInstruction.LoadField(typeof(ItemActionData), nameof(ItemActionData.invData)), + new CodeInstruction(OpCodes.Callvirt, prop_itemvalue), + new CodeInstruction(OpCodes.Ldloc_S, 6), + CodeInstruction.Call(typeof(ActionModuleMetaConsumer), nameof(ConsumeMetaData)), + }); + break; + } + } + + return codes; + } + + public bool CheckAndCacheMetaData(ItemValue itemValue, EntityAlive holdingEntity, string soundEmpty) + { + for (int i = 0; i < consumeDatas.Length; i++) + { + string consumeData = consumeDatas[i]; + float stock = (float)itemValue.GetMetadata(consumeData); + float consumption = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, float.MaxValue, holdingEntity, null, consumeTags[i]); + if (stock < consumption) + { + holdingEntity.PlayOneShot(soundEmpty); + return false; + } + consumeStocks[i] = stock; + consumeValues[i] = consumption; + } + return true; + } + + public void ConsumeMetaData(ItemValue itemValue, EntityAlive holdingEntity) + { + for (int i = 0; i < consumeDatas.Length; i++) + { + itemValue.SetMetadata(consumeDatas[i], consumeStocks[i] - consumeValues[i], TypedMetadataValue.TypeTag.Float); + holdingEntity.MinEventContext.Tags = consumeTags[i]; + holdingEntity.FireEvent(CustomEnums.onRechargeValueUpdate, true); + } + } + + //[HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPrefix] + //private bool Prefix_ExecuteAction(ItemActionData _actionData, bool _bReleased, ItemActionRanged __instance) + //{ + // ItemActionRanged.ItemActionDataRanged _data = _actionData as ItemActionRanged.ItemActionDataRanged; + // EntityAlive holdingEntity = _actionData.invData.holdingEntity; + // ItemValue itemValue = _actionData.invData.itemValue; + // if (!_bReleased) + // { + // int burstCount = __instance.GetBurstCount(_actionData); + // if (holdingEntity.inventory.holdingItemItemValue.PercentUsesLeft <= 0f || (_data.curBurstCount >= burstCount && burstCount != -1) || (!__instance.InfiniteAmmo && itemValue.Meta <= 0)) + // { + // return true; + // } + + // for (int i = 0; i < consumeDatas.Length; i++) + // { + // string consumeData = consumeDatas[i]; + // float stock = (float)itemValue.GetMetadata(consumeData); + // float consumption = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, float.MaxValue, _actionData.invData.holdingEntity, null, consumeTags[i]); + // if (stock < consumption) + // { + // if (!_data.bPressed) + // { + // holdingEntity.PlayOneShot(__instance.soundEmpty); + // _data.bPressed = true; + // } + // return false; + // } + // consumeStocks[i] = stock; + // consumeValues[i] = consumption; + // } + + // for (int i = 0; i < consumeDatas.Length; i++) + // { + // itemValue.SetMetadata(consumeDatas[i], consumeStocks[i] - consumeValues[i], TypedMetadataValue.TypeTag.Float); + // holdingEntity.MinEventContext.Tags = consumeTags[i]; + // holdingEntity.FireEvent(CustomEnums.onRechargeValueUpdate, true); + // } + // } + // return true; + //} +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleMetaRecharger.cs b/Scripts/Items/ModularActions/ActionModuleMetaRecharger.cs new file mode 100644 index 0000000..2a1894b --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleMetaRecharger.cs @@ -0,0 +1,166 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System; +using UniLinq; +using UnityEngine; + +[TypeTarget(typeof(ItemActionRanged)), ActionDataTarget(typeof(MetaRechargerData))] +public class ActionModuleMetaRecharger +{ + public struct RechargeTags + { + public FastTags tagsOriginal; + public FastTags tagsInterval; + public FastTags tagsMaximum; + public FastTags tagsValue; + public FastTags tagsDecrease; + public FastTags tagsDecreaseInterval; + } + + public string[] rechargeDatas; + public RechargeTags[] rechargeTags; + private static readonly FastTags TagsInterval = FastTags.Parse("RechargeDataInterval"); + private static readonly FastTags TagsMaximum = FastTags.Parse("RechargeDataMaximum"); + private static readonly FastTags TagsValue = FastTags.Parse("RechargeDataValue"); + private static readonly FastTags TagsDecrease = FastTags.Parse("RechargeDataDecrease"); + private static readonly FastTags TagsDecreaseInterval = FastTags.Parse("RechargeDecreaseInterval"); + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + private void Postfix_ReadFrom(DynamicProperties _props, ItemAction __instance) + { + rechargeDatas = null; + rechargeTags = null; + string rechargeData = string.Empty; + _props.Values.TryGetValue("RechargeData", out rechargeData); + _props.Values.TryGetValue("RechargeTags", out string tags); + FastTags commonTags = string.IsNullOrEmpty(tags) ? FastTags.none : FastTags.Parse(tags); + if (string.IsNullOrEmpty(rechargeData)) + { + Log.Error($"No recharge data found on item {__instance.item.Name} action {__instance.ActionIndex}"); + return; + } + rechargeDatas = rechargeData.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => s.Trim()).ToArray(); + rechargeTags = rechargeDatas.Select(s => + { + var _tags = FastTags.Parse(s) | commonTags; + return new RechargeTags + { + tagsOriginal = _tags, + tagsInterval = _tags | TagsInterval, + tagsMaximum = _tags | TagsMaximum, + tagsValue = _tags | TagsValue, + tagsDecrease = _tags | TagsDecrease, + tagsDecreaseInterval = _tags | TagsDecreaseInterval, + }; + }).ToArray(); + } + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPrefix] + private bool Prefix_StartHolding(ItemActionData _data, MetaRechargerData __customData) + { + EntityAlive holdingEntity = _data.invData.holdingEntity; + if (holdingEntity.isEntityRemote) + return true; + for (int i = 0; i < rechargeDatas.Length; i++) + { + holdingEntity.MinEventContext.Tags = rechargeTags[i].tagsOriginal; + holdingEntity.FireEvent(CustomEnums.onRechargeValueUpdate, true); + } + return true; + } + + public class MetaRechargerData : IBackgroundInventoryUpdater + { + private ActionModuleMetaRecharger module; + private float lastUpdateTime, lastDecreaseTime; + private int indexOfAction; + + public int Index => indexOfAction; + + public MetaRechargerData(ItemInventoryData _invData, int _indexOfAction, ActionModuleMetaRecharger _rechargeModule) + { + module = _rechargeModule; + indexOfAction = _indexOfAction; + lastUpdateTime = lastDecreaseTime = Time.time; + if (_rechargeModule.rechargeDatas == null) + return; + + BackgroundInventoryUpdateManager.RegisterUpdater(_invData.holdingEntity, _invData.slotIdx, this); + } + + public bool OnUpdate(ItemInventoryData invData) + { + ItemValue itemValue = invData.itemValue; + EntityAlive holdingEntity = invData.holdingEntity; + holdingEntity.MinEventContext.ItemInventoryData = invData; + holdingEntity.MinEventContext.ItemValue = itemValue; + holdingEntity.MinEventContext.ItemActionData = invData.actionData[indexOfAction]; + float curTime = Time.time; + bool res = false; + for (int i = 0; i < module.rechargeDatas.Length; i++) + { + string rechargeData = module.rechargeDatas[i]; + RechargeTags rechargeTag = module.rechargeTags[i]; + float updateInterval = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, float.MaxValue, holdingEntity, null, rechargeTag.tagsInterval); + float decreaseInterval = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, float.MaxValue, holdingEntity, null, rechargeTag.tagsDecreaseInterval); + float deltaTime = curTime - lastUpdateTime; + float deltaDecreaseTime = curTime - lastDecreaseTime; + if (deltaTime > updateInterval || deltaDecreaseTime > decreaseInterval) + { + //Log.Out($"last update time {lastUpdateTime} cur time {curTime} update interval {updateInterval}"); + float cur; + if (!itemValue.HasMetadata(rechargeData)) + { + itemValue.SetMetadata(rechargeData, 0, TypedMetadataValue.TypeTag.Float); + cur = 0; + } + else + { + cur = (float)itemValue.GetMetadata(rechargeData); + } + float max = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, 0, holdingEntity, null, rechargeTag.tagsMaximum); + bool modified = false; + if (cur > max) + { + if (deltaDecreaseTime > decreaseInterval) + { + //the result updated here won't exceed max so it's set somewhere else, decrease slowly + float dec = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, float.MaxValue, holdingEntity, null, rechargeTag.tagsDecrease); + cur = Mathf.Max(cur - dec, max); + lastDecreaseTime = curTime; + modified = true; + } + lastUpdateTime = curTime; + } + else + { + if (cur < max && deltaTime > updateInterval) + { + //add up and clamp to max + float add = EffectManager.GetValue(CustomEnums.CustomTaggedEffect, itemValue, 0, holdingEntity, null, rechargeTag.tagsValue); + cur = Mathf.Min(cur + add, max); + lastUpdateTime = curTime; + modified = true; + } + //always set lastDecreaseTime if not overcharged, since we don't want overcharged data to decrease right after it's charged + lastDecreaseTime = curTime; + } + + if (modified) + { + itemValue.SetMetadata(rechargeData, cur, TypedMetadataValue.TypeTag.Float); + } + if (invData.slotIdx == holdingEntity.inventory.holdingItemIdx && invData.slotIdx >= 0) + { + holdingEntity.MinEventContext.Tags = rechargeTag.tagsOriginal; + itemValue.FireEvent(CustomEnums.onRechargeValueUpdate, holdingEntity.MinEventContext); + //Log.Out($"action index is {holdingEntity.MinEventContext.ItemActionData.indexInEntityOfAction} after firing event"); + } + res |= modified; + } + } + return res; + } + } +} diff --git a/Scripts/Items/ModularActions/ActionModuleMultiActionFix.cs b/Scripts/Items/ModularActions/ActionModuleMultiActionFix.cs new file mode 100644 index 0000000..009fbfc --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleMultiActionFix.cs @@ -0,0 +1,222 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; + +[TypeTarget(typeof(ItemActionAttack)), ActionDataTarget(typeof(MultiActionData))] +public class ActionModuleMultiActionFix +{ + private int actionIndex; + public string GetDisplayType(ItemValue itemValue) + { + string displayType = itemValue.GetPropertyOverrideForAction("DisplayType", null, actionIndex); + if (string.IsNullOrEmpty(displayType)) + { + displayType = itemValue.ItemClass.DisplayType; + } + return displayType; + } + + [HarmonyPatch(nameof(ItemAction.ReadFrom)), MethodTargetPostfix] + public void Postfix_ReadFrom(ItemActionAttack __instance) + { + actionIndex = __instance.ActionIndex; + } + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPrefix] + public bool Prefix_StartHolding(ItemActionData _data, out ItemActionData __state) + { + SetAndSaveItemActionData(_data, out __state); + return true; + } + + [HarmonyPatch(nameof(ItemAction.StartHolding)), MethodTargetPostfix] + public void Postfix_StartHolding(ItemActionData _data, ItemActionData __state) + { + RestoreItemActionData(_data, __state); + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + public void Postfix_OnModificationChanged_ItemActionRanged(ItemActionData _data, ItemActionAttack __instance) + { + var rangedData = _data as ItemActionRanged.ItemActionDataRanged; + if (rangedData != null) + { + string muzzleName; + string indexExtension = (_data.indexInEntityOfAction > 0 ? _data.indexInEntityOfAction.ToString() : ""); + if (rangedData.IsDoubleBarrel) + { + muzzleName = _data.invData.itemValue.GetPropertyOverrideForAction($"Muzzle_L_Name", $"Muzzle_L{indexExtension}", _data.indexInEntityOfAction); + rangedData.muzzle = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, muzzleName) ?? rangedData.muzzle; + muzzleName = _data.invData.itemValue.GetPropertyOverrideForAction($"Muzzle_R_Name", $"Muzzle_R{indexExtension}", _data.indexInEntityOfAction); + rangedData.muzzle2 = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, muzzleName) ?? rangedData.muzzle2; + } + else + { + muzzleName = _data.invData.itemValue.GetPropertyOverrideForAction($"Muzzle_Name", $"Muzzle{indexExtension}", _data.indexInEntityOfAction); + rangedData.muzzle = AnimationRiggingManager.GetTransformOverrideByName(rangedData.invData.model, muzzleName) ?? rangedData.muzzle; + } + } + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + public void Postfix_OnModificationChanged_ItemActionLauncher(ItemActionData _data, ItemActionAttack __instance) + { + Postfix_OnModificationChanged_ItemActionRanged(_data, __instance); + if (_data is ItemActionLauncher.ItemActionDataLauncher launcherData) + { + string indexExtension = (_data.indexInEntityOfAction > 0 ? _data.indexInEntityOfAction.ToString() : ""); + string jointName = _data.invData.itemValue.GetPropertyOverrideForAction($"ProjectileJoint_Name", $"ProjectileJoint{indexExtension}", _data.indexInEntityOfAction); + launcherData.projectileJoint = AnimationRiggingManager.GetTransformOverrideByName(launcherData.invData.model, jointName) ?? launcherData.projectileJoint; + } + } + + [HarmonyPatch(nameof(ItemAction.StopHolding)), MethodTargetPrefix] + public bool Prefix_StopHolding(ItemActionData _data, out ItemActionData __state) + { + SetAndSaveItemActionData(_data, out __state); + return true; + } + + [HarmonyPatch(nameof(ItemAction.StopHolding)), MethodTargetPostfix] + public void Postfix_StopHolding(ItemActionData _data, ItemActionData __state) + { + RestoreItemActionData(_data, __state); + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemAction.ItemActionEffects)), MethodTargetPrefix] + public bool Prefix_ItemActionEffects(ItemActionData _actionData, out ItemActionData __state) + { + SetAndSaveItemActionData(_actionData, out __state); + return true; + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemAction.ItemActionEffects)), MethodTargetPostfix] + public void Postfix_ItemActionEffects(ItemActionData _actionData, ItemActionData __state) + { + RestoreItemActionData(_actionData, __state); + } + + [HarmonyPatch(nameof(ItemAction.CancelAction)), MethodTargetPrefix] + public bool Prefix_CancelAction(ItemActionData _actionData, out ItemActionData __state) + { + SetAndSaveItemActionData(_actionData, out __state); + return true; + } + + [HarmonyPatch(nameof(ItemAction.CancelAction)), MethodTargetPostfix] + public void Postfix_CancelAction(ItemActionData _actionData, ItemActionData __state) + { + RestoreItemActionData(_actionData, __state); + } + + [HarmonyPatch(nameof(ItemActionAttack.CancelReload)), MethodTargetPrefix] + public bool Prefix_CancelReload(ItemActionData _actionData, out ItemActionData __state) + { + SetAndSaveItemActionData(_actionData, out __state); + return true; + } + + [HarmonyPatch(nameof(ItemActionAttack.CancelReload)), MethodTargetPostfix] + public void Postfix_CancelReload(ItemActionData _actionData, ItemActionData __state) + { + RestoreItemActionData(_actionData, __state); + } + + [HarmonyPatch(nameof(ItemActionAttack.ReloadGun)), MethodTargetPrefix] + public bool Prefix_ReloadGun(ItemActionData _actionData) + { + //int reloadAnimationIndex = MultiActionManager.GetMetaIndexForActionIndex(_actionData.invData.holdingEntity.entityId, _actionData.indexInEntityOfAction); + _actionData.invData.holdingEntity.emodel?.avatarController?.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, _actionData.indexInEntityOfAction, false); + _actionData.invData.holdingEntity.MinEventContext.ItemActionData = _actionData; + //MultiActionManager.GetMappingForEntity(_actionData.invData.holdingEntity.entityId)?.SaveMeta(); + return true; + } + + [HarmonyPatch(nameof(ItemAction.OnHUD)), MethodTargetPrefix] + public bool Prefix_OnHUD(ItemActionData _actionData) + { + if (_actionData.invData?.holdingEntity?.MinEventContext?.ItemActionData == null || _actionData.indexInEntityOfAction != _actionData.invData.holdingEntity.MinEventContext.ItemActionData.indexInEntityOfAction) + return false; + return true; + } + + //[MethodTargetPrefix(nameof(ItemActionAttack.ExecuteAction), typeof(ItemActionRanged))] + //public bool Prefix_ExecuteAction(ItemActionData _actionData, MultiActionData __customData) + //{ + // //when executing action, set last action index so that correct accuracy is used for drawing crosshair + // if (_actionData.invData.holdingEntity is EntityPlayerLocal player) + // { + // ((ItemActionRanged.ItemActionDataRanged)_actionData).lastAccuracy = __customData.lastAccuracy; + // } + // return true; + //} + + //[MethodTargetPrefix("updateAccuracy", typeof(ItemActionRanged))] + //public bool Prefix_updateAccuracy(ItemActionData _actionData, MultiActionData __customData) + //{ + // if (_actionData.invData.holdingEntity is EntityPlayerLocal player && MultiActionManager.GetActionIndexForEntityID(player.entityId) == _actionData.indexInEntityOfAction) + // return true; + // //always update custom accuracy + // ItemActionRanged.ItemActionDataRanged rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + // (rangedData.lastAccuracy, __customData.lastAccuracy) = (__customData.lastAccuracy, rangedData.lastAccuracy); + // return true; + //} + + //[MethodTargetPostfix("updateAccuracy", typeof(ItemActionRanged))] + //public void Postfix_updateAccuracy(ItemActionData _actionData, MultiActionData __customData) + //{ + // //retain rangedData accuracy if it's the last executed action + // ItemActionRanged.ItemActionDataRanged rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + // if (_actionData.invData.holdingEntity is EntityPlayerLocal player && MultiActionManager.GetActionIndexForEntityID(player.entityId) == _actionData.indexInEntityOfAction) + // { + // __customData.lastAccuracy = rangedData.lastAccuracy; + // } + // else + // { + // (rangedData.lastAccuracy, __customData.lastAccuracy) = (__customData.lastAccuracy, rangedData.lastAccuracy); + // } + //} + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemActionRanged.onHoldingEntityFired)), MethodTargetPrefix] + public bool Prefix_onHoldingEntityFired(ItemActionData _actionData) + { + if (!_actionData.invData.holdingEntity.isEntityRemote) + { + _actionData.invData.holdingEntity?.emodel?.avatarController.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, _actionData.indexInEntityOfAction); + //_actionData.invData.holdingEntity?.emodel?.avatarController.CancelEvent("WeaponFire"); + } + return true; + } + + //[MethodTargetPostfix("onHoldingEntityFired", typeof(ItemActionRanged))] + //public void Postfix_onHoldingEntityFired(ItemActionData _actionData, MultiActionData __customData) + //{ + // //after firing, if it's the last executed action then update custom accuracy + // if (_actionData.invData.holdingEntity is EntityPlayerLocal player && MultiActionManager.GetActionIndexForEntityID(player.entityId) == _actionData.indexInEntityOfAction) + // { + // __customData.lastAccuracy = ((ItemActionRanged.ItemActionDataRanged)_actionData).lastAccuracy; + // } + //} + + public static void SetAndSaveItemActionData(ItemActionData _actionData, out ItemActionData lastActionData) + { + lastActionData = _actionData.invData.holdingEntity.MinEventContext.ItemActionData; + _actionData.invData.holdingEntity.MinEventContext.ItemActionData = _actionData; + } + + public static void RestoreItemActionData(ItemActionData _actionData, ItemActionData lastActionData) + { + if (lastActionData != null) + _actionData.invData.holdingEntity.MinEventContext.ItemActionData = lastActionData; + } + + public class MultiActionData + { + public float lastAccuracy; + + public MultiActionData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleMultiActionFix _module) + { + + } + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleMultiBarrel.cs b/Scripts/Items/ModularActions/ActionModuleMultiBarrel.cs new file mode 100644 index 0000000..72b245e --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleMultiBarrel.cs @@ -0,0 +1,302 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using KFCommonUtilityLib.Scripts.Utilities; +using System.Collections.Generic; +using System.Reflection.Emit; +using UniLinq; +using UnityEngine; + +[TypeTarget(typeof(ItemActionRanged)), ActionDataTarget(typeof(MultiBarrelData))] +public class ActionModuleMultiBarrel +{ + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + public void Postfix_OnModificationChanged(ItemActionData _data, MultiBarrelData __customData, ItemActionRanged __instance) + { + int actionIndex = _data.indexInEntityOfAction; + string originalValue = false.ToString(); + __instance.Properties.ParseString("MuzzleIsPerRound", ref originalValue); + __customData.muzzleIsPerRound = bool.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("MuzzleIsPerRound", originalValue, actionIndex)); + + originalValue = false.ToString(); + __instance.Properties.ParseString("OneRoundMultiShot", ref originalValue); + __customData.oneRoundMultishot = bool.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("OneRoundMultiShot", originalValue, actionIndex)); + + originalValue = 1.ToString(); + __instance.Properties.ParseString("RoundsPerShot", ref originalValue); + __customData.roundsPerShot = int.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("RoundsPerShot", originalValue, actionIndex)); + + originalValue = 1.ToString(); + __instance.Properties.ParseString("BarrelCount", ref originalValue); + __customData.barrelCount = int.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("BarrelCount", originalValue, actionIndex)); + + //Log.Out($"MuzzleIsPerRound: {__customData.muzzleIsPerRound} OneRoundMultiShot: {__customData.oneRoundMultishot} RoundsPerShot: {__customData.roundsPerShot} BarrelCount: {__customData.barrelCount}"); + + __customData.muzzles = new Transform[__customData.barrelCount]; + __customData.projectileJoints = new Transform[__customData.barrelCount]; + + for (int i = 0; i < __customData.barrelCount; i++) + { + string muzzleName = _data.invData.itemValue.GetPropertyOverrideForAction($"MBMuzzle{i}_Name", $"MBMuzzle{i}", actionIndex); + __customData.muzzles[i] = AnimationRiggingManager.GetTransformOverrideByName(_data.invData.model, muzzleName); + string jointName = _data.invData.itemValue.GetPropertyOverrideForAction($"MBProjectileJoint{i}_Name", $"MBProjectileJoint{i}", actionIndex); + __customData.projectileJoints[i] = AnimationRiggingManager.GetTransformOverrideByName(_data.invData.model, jointName); + } + + int meta = MultiActionUtils.GetMetaByActionIndex(_data.invData.itemValue, actionIndex); + __customData.SetCurrentBarrel(meta); + ((ItemActionRanged.ItemActionDataRanged)_data).IsDoubleBarrel = false; + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemAction.StartHolding)), MethodTargetPrefix] + public void Prefix_StartHolding_ItemActionLauncher(ItemActionData _data, ItemActionLauncher __instance, MultiBarrelData __customData) + { + ItemActionLauncher.ItemActionDataLauncher launcherData = _data as ItemActionLauncher.ItemActionDataLauncher; + launcherData.projectileJoint = __customData.projectileJoints[0]; + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemAction.StartHolding)), MethodTargetPostfix] + public void Postfix_StartHolding_ItemActionLauncher(ItemActionData _data, ItemActionLauncher __instance, MultiBarrelData __customData) + { + ItemActionLauncher.ItemActionDataLauncher launcherData = _data as ItemActionLauncher.ItemActionDataLauncher; + if (launcherData?.projectileInstance != null && __customData.oneRoundMultishot && __customData.roundsPerShot > 1) + { + int count = launcherData.projectileInstance.Count; + int times = __customData.roundsPerShot - 1; + for (int i = 0; i < times; i++) + { + launcherData.projectileJoint = __customData.projectileJoints[i + 1]; + for (int j = 0; j < count; j++) + { + launcherData.projectileInstance.Add(__instance.instantiateProjectile(_data)); + } + } + } + launcherData.projectileJoint = __customData.projectileJoints[__customData.curBarrelIndex]; + } + + [HarmonyPatch(nameof(ItemActionRanged.getUserData)), MethodTargetPostfix] + public void Postfix_getUserData(MultiBarrelData __customData, ref int __result) + { + __result |= ((byte)__customData.curBarrelIndex) << 8; + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.ItemActionEffects)), MethodTargetPrefix] + public bool Prefix_ItemActionEffects_ItemActionRanged(ItemActionData _actionData, int _userData, int _firingState, MultiBarrelData __customData) + { + ItemActionRanged.ItemActionDataRanged rangedData = _actionData as ItemActionRanged.ItemActionDataRanged; + if (rangedData != null && _firingState != 0) + { + byte index = (byte)(_userData >> 8); + rangedData.muzzle = __customData.muzzles[index]; + __customData.SetAnimatorParam(index); + } + return true; + } + + [HarmonyPatch(typeof(ItemActionLauncher), nameof(ItemAction.ItemActionEffects)), MethodTargetPrefix] + public bool Prefix_ItemActionEffects_ItemActionLauncher(ItemActionData _actionData, int _userData, int _firingState, MultiBarrelData __customData) + { + ItemActionLauncher.ItemActionDataLauncher launcherData = _actionData as ItemActionLauncher.ItemActionDataLauncher; + if (launcherData != null) + { + launcherData.projectileJoint = __customData.projectileJoints[(byte)(_userData >> 8)]; + } + return Prefix_ItemActionEffects_ItemActionRanged(_actionData, _userData, _firingState, __customData); + } + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.ExecuteAction)), MethodTargetTranspiler] + private static IEnumerable Transpiler_ExecuteAction_ItemActionRanged(IEnumerable instructions, ILGenerator generator) + { + var codes = instructions.ToList(); + + var mtd_getmax = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.GetMaxAmmoCount)); + var mtd_consume = AccessTools.Method(typeof(ItemActionRanged), nameof(ItemActionRanged.ConsumeAmmo)); + var prop_instance = AccessTools.PropertyGetter(typeof(IModuleContainerFor), nameof(IModuleContainerFor.Instance)); + + Label loopStart = generator.DefineLabel(); + Label loopCondi = generator.DefineLabel(); + LocalBuilder lbd_data_module = generator.DeclareLocal(typeof(ActionModuleMultiBarrel.MultiBarrelData)); + LocalBuilder lbd_i = generator.DeclareLocal(typeof(int)); + LocalBuilder lbd_rounds = generator.DeclareLocal(typeof(int)); + for (int i = 0; i < codes.Count; i++) + { + //prepare loop and store local variables + if (codes[i].opcode == OpCodes.Stloc_S && ((LocalBuilder)codes[i].operand).LocalIndex == 6) + { + codes[i + 1].WithLabels(loopStart); + codes.InsertRange(i + 1, new[] + { + new CodeInstruction(OpCodes.Ldarg_1), + new CodeInstruction(OpCodes.Castclass, typeof(IModuleContainerFor)), + new CodeInstruction(OpCodes.Callvirt, prop_instance), + new CodeInstruction(OpCodes.Stloc_S, lbd_data_module), + new CodeInstruction(OpCodes.Ldc_I4_0), + new CodeInstruction(OpCodes.Stloc_S, lbd_i), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.roundsPerShot)), + new CodeInstruction(OpCodes.Stloc_S, lbd_rounds), + new CodeInstruction(OpCodes.Br_S, loopCondi), + }); + i += 11; + } + //one round multi shot check + else if (codes[i].Calls(mtd_consume)) + { + Label lbl = generator.DefineLabel(); + codes[i - 5].WithLabels(lbl); + codes.InsertRange(i - 5, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.oneRoundMultishot)), + new CodeInstruction(OpCodes.Brfalse_S, lbl), + new CodeInstruction(OpCodes.Ldloc_S, lbd_i), + new CodeInstruction(OpCodes.Ldc_I4_0), + new CodeInstruction(OpCodes.Bgt_S, codes[i - 3].operand) + }); + i += 6; + } + //loop conditions and cycle barrels + else if (codes[i].Calls(mtd_getmax)) + { + Label lbl_pre = generator.DefineLabel(); + Label lbl_post = generator.DefineLabel(); + CodeInstruction origin = codes[i - 2]; + codes.InsertRange(i - 2, new[] + { + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module).WithLabels(origin.ExtractLabels()), + CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.muzzleIsPerRound)), + new CodeInstruction(OpCodes.Brfalse_S, lbl_pre), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.Call(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.CycleBarrels)), + new CodeInstruction(OpCodes.Ldloc_S, 6).WithLabels(lbl_pre), + CodeInstruction.LoadField(typeof(EntityAlive), nameof(EntityAlive.inventory)), + CodeInstruction.Call(typeof(Inventory), nameof(Inventory.CallOnToolbeltChangedInternal)), + new CodeInstruction(OpCodes.Ldloc_S, lbd_i), + new CodeInstruction(OpCodes.Ldc_I4_1), + new CodeInstruction(OpCodes.Add), + new CodeInstruction(OpCodes.Stloc_S, lbd_i), + new CodeInstruction(OpCodes.Ldloc_S, lbd_i).WithLabels(loopCondi), + new CodeInstruction(OpCodes.Ldloc_S, lbd_rounds), + new CodeInstruction(OpCodes.Blt_S, loopStart), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.LoadField(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.muzzleIsPerRound)), + new CodeInstruction(OpCodes.Brtrue_S, lbl_post), + new CodeInstruction(OpCodes.Ldloc_S, lbd_data_module), + CodeInstruction.Call(typeof(ActionModuleMultiBarrel.MultiBarrelData), nameof(ActionModuleMultiBarrel.MultiBarrelData.CycleBarrels)) + }); + origin.WithLabels(lbl_post); + break; + } + } + + return codes; + } + + private static void LogInfo(int cur, int max) => Log.Out($"max rounds {max}, cur {cur}"); + + public class MultiBarrelData + { + public ItemInventoryData invData; + public int actionIndex; + public ActionModuleMultiBarrel module; + public bool muzzleIsPerRound; + public bool oneRoundMultishot; + public int roundsPerShot; + public int barrelCount; + public int curBarrelIndex; + public Transform[] muzzles; + public Transform[] projectileJoints; + + public MultiBarrelData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleMultiBarrel _module) + { + invData = _invData; + actionIndex = _indexInEntityOfAction; + module = _module; + } + + public void CycleBarrels() + { + curBarrelIndex = ++curBarrelIndex >= barrelCount ? 0 : curBarrelIndex; + //Log.Out($"cycle barrel index {curBarrelIndex}"); + } + + public void SetCurrentBarrel(int roundLeft) + { + if (muzzleIsPerRound) + { + int totalSwitches; + if (oneRoundMultishot) + { + totalSwitches = roundLeft * roundsPerShot; + } + else + { + totalSwitches = roundLeft; + } + int lastCycleSwitches = totalSwitches % barrelCount; + int barrelGroup = barrelCount / roundsPerShot; + curBarrelIndex = (barrelCount - lastCycleSwitches) / barrelGroup * barrelGroup; + } + else + { + if (oneRoundMultishot) + { + curBarrelIndex = barrelCount - (roundLeft % barrelCount); + } + else + { + curBarrelIndex = barrelCount - ((roundLeft + 1) / roundsPerShot) % barrelCount; + } + } + if (curBarrelIndex >= barrelCount) + { + curBarrelIndex = 0; + } + SetAnimatorParam(curBarrelIndex); + //Log.Out($"set barrel index {curBarrelIndex}"); + } + + public void SetAnimatorParam(int barrelIndex) + { + invData.holdingEntity.emodel.avatarController.UpdateInt("barrelIndex", barrelIndex, true); + //Log.Out($"set param index {barrelIndex}"); + } + } +} + +[HarmonyPatch] +public class MultiBarrelPatches +{ + + [HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateEnter))] + [HarmonyPostfix] + private static void Postfix_OnStateEnter_AnimatorRangedReloadState(AnimatorRangedReloadState __instance) + { + ItemActionLauncher.ItemActionDataLauncher launcherData = __instance.actionData as ItemActionLauncher.ItemActionDataLauncher; + if (launcherData != null && launcherData is IModuleContainerFor dataModule && dataModule.Instance.oneRoundMultishot && dataModule.Instance.roundsPerShot > 1) + { + int count = launcherData.projectileInstance.Count; + int times = dataModule.Instance.roundsPerShot - 1; + for (int i = 0; i < count; i++) + { + for (int j = 0; j < times; j++) + { + launcherData.projectileJoint = dataModule.Instance.projectileJoints[j + 1]; + launcherData.projectileInstance.Insert(i * (times + 1) + j + 1, ((ItemActionLauncher)__instance.actionRanged).instantiateProjectile(launcherData)); + } + } + } + } + + [HarmonyPatch(typeof(AnimatorRangedReloadState), nameof(AnimatorRangedReloadState.OnStateExit))] + [HarmonyPostfix] + private static void Postfix_OnStateExit_AnimatorRangedReloadState(AnimatorRangedReloadState __instance) + { + if (__instance.actionData is IModuleContainerFor dataModule) + { + dataModule.Instance.SetCurrentBarrel(__instance.actionData.invData.itemValue.Meta); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleProceduralAiming.cs b/Scripts/Items/ModularActions/ActionModuleProceduralAiming.cs new file mode 100644 index 0000000..8b489e4 --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleProceduralAiming.cs @@ -0,0 +1,271 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System.Collections.Generic; +using UnityEngine; + +[TypeTarget(typeof(ItemActionZoom)), ActionDataTarget(typeof(ProceduralAimingData))] +public class ActionModuleProceduralAiming +{ + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + public void Postfix_OnModificationsChanged(ItemActionZoom __instance, ItemActionData _data, ProceduralAimingData __customData) + { + if (_data is IModuleContainerFor dataModule) + { + __customData.zoomInTime = dataModule.Instance.module.zoomInTimeBase / dataModule.Instance.module.aimSpeedModifierBase; + __customData.ergoData = dataModule.Instance; + } + else + { + float zoomInTimeBase = 0.3f; + __instance.Properties.ParseFloat("ZoomInTimeBase", ref zoomInTimeBase); + float aimSpeedModifierBase = 1f; + __instance.Properties.ParseFloat("AimSpeedModifierBase", ref aimSpeedModifierBase); + __customData.zoomInTime = zoomInTimeBase / aimSpeedModifierBase; + __customData.ergoData = null; + } + + __customData.playerOriginTransform = null; + __customData.playerCameraPosRef = _data.invData.holdingEntity is EntityPlayerLocal player && player.bFirstPersonView ? player.cameraTransform : null; + var targets = AnimationRiggingManager.GetRigTargetsFromPlayer(_data.invData.holdingEntity); + if (__customData.playerCameraPosRef) + { + if (targets.ItemFpv) + { + if (targets is RigTargets) + { + __customData.isRigWeapon = true; + __customData.playerOriginTransform = targets.ItemAnimator.transform; + __customData.rigWeaponLocalPosition = __customData.playerOriginTransform.localPosition; + __customData.rigWeaponLocalRotation = __customData.playerOriginTransform.localRotation; + } + else + { + __customData.isRigWeapon = false; + __customData.playerOriginTransform = __customData.playerCameraPosRef.FindInAllChildren("Hips"); + } + __customData.playerCameraPosRef = targets.ItemFpv.Find("PlayerCameraPositionReference"); + } + else + { + __customData.playerCameraPosRef = null; + } + } + if (__customData.playerCameraPosRef) + { + __customData.aimRefTransform = targets.ItemFpv.Find("ScopeBasePositionReference"); + if (__customData.aimRefTransform) + { + var scopeRefTrans = __customData.aimRefTransform.Find("ScopePositionReference"); + if (!scopeRefTrans) + { + scopeRefTrans = new GameObject("ScopePositionReference").transform; + scopeRefTrans.SetParent(__customData.aimRefTransform, false); + } + scopeRefTrans.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); + scopeRefTrans.localScale = Vector3.one; + __customData.aimRefTransform = scopeRefTrans; + } + } + else + { + __customData.aimRefTransform = null; + } + + __customData.ResetAiming(); + __customData.UpdateCurrentReference(true); + } + + [HarmonyPatch(nameof(ItemAction.StopHolding)), MethodTargetPostfix] + public void Postfix_StopHolding(ProceduralAimingData __customData) + { + __customData.ResetAiming(); + } + + //[HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPostfix] + //public void Postfix_ExecuteAction(ProceduralAimingData __customData, ItemActionData _actionData) + //{ + // if (__customData.isAiming != ((ItemActionZoom.ItemActionDataZoom)_actionData).aimingValue) + // { + // __customData.UpdateCurrentReference(); + // __customData.isAiming = ((ItemActionZoom.ItemActionDataZoom)_actionData).aimingValue; + // } + //} + + public class ProceduralAimingData + { + public ActionModuleErgoAffected.ErgoData ergoData; + public float zoomInTime; + public Transform aimRefTransform; + public Transform playerCameraPosRef; + public Transform playerOriginTransform; + public bool isRigWeapon; + public Vector3 rigWeaponLocalPosition; + public Quaternion rigWeaponLocalRotation; + + public bool isAiming; + public int curAimRefIndex = -1; + //move curAimRefOffset towards aimRefOffset first, then move curAimOffset towards curAimRefOffset + public Vector3 aimRefPosOffset; + public Quaternion aimRefRotOffset; + public Vector3 curAimPosOffset; + public Quaternion curAimRotOffset; + private Vector3 curAimPosVelocity; + private Quaternion curAimRotVelocity; + private Vector3 targetSwitchPosVelocity; + private Quaternion targetSwitchRotVelocity; + public List registeredReferences = new List(); + private EntityPlayerLocal holdingEntity; + private int CurAimRefIndex + { + get + { + for (int i = registeredReferences.Count - 1; i >= 0; i--) + { + if (registeredReferences[i].gameObject.activeInHierarchy) + { + return i; + } + } + return -1; + } + } + + private AimReference CurAimRef => curAimRefIndex >= 0 && curAimRefIndex < registeredReferences.Count ? registeredReferences[curAimRefIndex] : null; + + public ProceduralAimingData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleProceduralAiming _module) + { + holdingEntity = _invData.holdingEntity as EntityPlayerLocal; + } + + public void ResetAiming() + { + isAiming = false; + curAimRefIndex = -1; + aimRefPosOffset = Vector3.zero; + aimRefRotOffset = Quaternion.identity; + if (aimRefTransform) + { + aimRefTransform.SetLocalPositionAndRotation(Vector3.zero, Quaternion.identity); + } + curAimPosOffset = Vector3.zero; + curAimRotOffset = Quaternion.identity; + curAimPosVelocity = Vector3.zero; + curAimRotVelocity = Quaternion.identity; + targetSwitchPosVelocity = Vector3.zero; + targetSwitchRotVelocity = Quaternion.identity; + if (isRigWeapon && playerOriginTransform) + { + playerOriginTransform.localPosition = rigWeaponLocalPosition; + playerOriginTransform.localRotation = rigWeaponLocalRotation; + } + } + + public bool RegisterGroup(AimReference[] group, string name) + { + if (holdingEntity && holdingEntity.bFirstPersonView) + { + foreach (var reference in group) + { + if (reference.index == -1) + { + reference.index = registeredReferences.Count; + registeredReferences.Add(reference); + } + } + UpdateCurrentReference(); + //Log.Out($"Register group {name}\n{StackTraceUtility.ExtractStackTrace()}"); + return true; + } + return false; + } + + public void UpdateCurrentReference(bool snapTo = false) + { + curAimRefIndex = CurAimRefIndex; + AimReference curAimRef = CurAimRef; + if (aimRefTransform && curAimRef) + { + aimRefPosOffset = curAimRef.positionOffset; + aimRefRotOffset = curAimRef.rotationOffset; + if (curAimRef.asReference) + { + aimRefPosOffset -= Vector3.Project(aimRefPosOffset - aimRefTransform.parent.InverseTransformPoint(playerCameraPosRef.position), aimRefRotOffset * Vector3.forward); + } + if (snapTo) + { + aimRefTransform.localPosition = aimRefPosOffset; + aimRefTransform.localRotation = aimRefRotOffset; + } + } + + for (int i = 0; i < registeredReferences.Count; i++) + { + registeredReferences[i].UpdateEnableState(isAiming && curAimRefIndex == i); + } + } + + public void LateUpdateAiming() + { + if (aimRefTransform && playerCameraPosRef && playerOriginTransform && CurAimRef) + { + if (isRigWeapon) + { + playerOriginTransform.SetLocalPositionAndRotation(rigWeaponLocalPosition, rigWeaponLocalRotation); + } + float zoomInTimeMod = ergoData == null ? zoomInTime : zoomInTime / ergoData.ModifiedErgo; + zoomInTimeMod *= 0.25f; + //move aimRef towards target + aimRefTransform.localPosition = Vector3.SmoothDamp(aimRefTransform.localPosition, aimRefPosOffset, ref targetSwitchPosVelocity, 0.075f); + aimRefTransform.localRotation = QuaternionUtil.SmoothDamp(aimRefTransform.localRotation, aimRefRotOffset, ref targetSwitchRotVelocity, 0.075f); + //calculate current target aim offset + Vector3 aimTargetPosOffset = playerCameraPosRef.InverseTransformDirection(playerCameraPosRef.position - aimRefTransform.position); + Quaternion aimTargetRotOffset = playerCameraPosRef.localRotation * Quaternion.Inverse(aimRefTransform.parent.localRotation * aimRefTransform.localRotation); + //move current aim offset towards target aim offset + if (isAiming) + { + curAimPosOffset = Vector3.SmoothDamp(curAimPosOffset, aimTargetPosOffset, ref curAimPosVelocity, zoomInTimeMod); + curAimRotOffset = QuaternionUtil.SmoothDamp(curAimRotOffset, aimTargetRotOffset, ref curAimRotVelocity, zoomInTimeMod); + } + else + { + curAimPosOffset = Vector3.SmoothDamp(curAimPosOffset, Vector3.zero, ref curAimPosVelocity, zoomInTimeMod); + curAimRotOffset = QuaternionUtil.SmoothDamp(curAimRotOffset, Quaternion.identity, ref curAimRotVelocity, zoomInTimeMod); + } + //apply offset to player + if (isRigWeapon) + { + (playerCameraPosRef.parent.rotation * curAimRotOffset * Quaternion.Inverse(playerCameraPosRef.parent.rotation)).ToAngleAxis(out var angle, out var axis); + playerOriginTransform.RotateAround(aimRefTransform.position, axis, angle); + playerOriginTransform.position += playerCameraPosRef.TransformDirection(curAimPosOffset); + } + else + { + playerOriginTransform.position += playerCameraPosRef.TransformDirection(curAimPosOffset); + (playerCameraPosRef.parent.rotation * curAimRotOffset * Quaternion.Inverse(playerCameraPosRef.parent.rotation)).ToAngleAxis(out var angle, out var axis); + playerOriginTransform.RotateAround(aimRefTransform.position, axis, angle); + } + } + } + } +} + +[HarmonyPatch] +public static class ProceduralAimingPatches +{ + [HarmonyPatch(typeof(EntityPlayerLocal), nameof(EntityPlayerLocal.LateUpdate))] + [HarmonyPostfix] + private static void Postfix_LateUpdate_EntityPlayerLocal(EntityPlayerLocal __instance) + { + if (__instance.inventory?.holdingItemData?.actionData?[1] is IModuleContainerFor module) + { + if (__instance.AimingGun != module.Instance.isAiming) + { + module.Instance.isAiming = __instance.AimingGun; + module.Instance.UpdateCurrentReference(true); + } + module.Instance.LateUpdateAiming(); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleRampUp.cs b/Scripts/Items/ModularActions/ActionModuleRampUp.cs new file mode 100644 index 0000000..cbca03c --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleRampUp.cs @@ -0,0 +1,276 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.Utilities; +using UnityEngine; +using static ItemActionRanged; + +[TypeTarget(typeof(ItemActionRanged)), ActionDataTarget(typeof(RampUpData))] +public class ActionModuleRampUp +{ + public enum State + { + RampUp, + Stable, + RampDown + } + + private readonly static int prepareHash = Animator.StringToHash("prepare"); + private readonly static int prepareSpeedHash = Animator.StringToHash("prepareSpeed"); + private readonly static int rampHash = Animator.StringToHash("ramp"); + private readonly static int prepareRatioHash = Animator.StringToHash("prepareRatio"); + private readonly static int rampRatioHash = Animator.StringToHash("rampRatio"); + private readonly static int totalRatioHash = Animator.StringToHash("totalRatio"); + + [HarmonyPatch(nameof(ItemAction.OnHoldingUpdate)), MethodTargetPostfix] + public void Postfix_OnHoldingUpdate(ItemActionData _actionData, RampUpData __customData, ItemActionRanged __instance) + { + var rangedData = _actionData as ItemActionDataRanged; + __customData.originalDelay = rangedData.Delay; + if (rangedData.invData.holdingEntity.isEntityRemote) + return; + + bool aiming = rangedData.invData.holdingEntity.AimingGun; + bool isRampUp = ((rangedData.bPressed && !rangedData.bReleased && __instance.notReloading(rangedData) && rangedData.curBurstCount < __instance.GetBurstCount(rangedData)) || (__customData.zoomPrepare && aiming)) && (__instance.InfiniteAmmo || _actionData.invData.itemValue.Meta > 0) && _actionData.invData.itemValue.PercentUsesLeft > 0; + UpdateTick(__customData, _actionData, isRampUp); + if (__customData.rampRatio > 0) + { + rangedData.Delay /= __customData.rampRatio >= 1f ? __customData.maxMultiplier : __customData.rampRatio * (__customData.maxMultiplier - 1f) + 1f; + } + } + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + public void Postfix_OnModificationsChanged(ItemActionData _data, RampUpData __customData, ItemActionRanged __instance) + { + int actionIndex = __instance.ActionIndex; + string originalValue = 1.ToString(); + __instance.Properties.ParseString("RampMultiplier", ref originalValue); + __customData.maxMultiplier = Mathf.Max(float.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("RampMultiplier", originalValue, actionIndex)), 1); + + originalValue = 0.ToString(); + __instance.Properties.ParseString("RampUpTime", ref originalValue); + __customData.rampUpTime = float.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("RampTime", originalValue, actionIndex)); + + originalValue = string.Empty; + __instance.Properties.ParseString("RampUpSound", ref originalValue); + __customData.rampUpSound = _data.invData.itemValue.GetPropertyOverrideForAction("RampStartSound", originalValue, actionIndex); + + originalValue = 0.ToString(); + __instance.Properties.ParseString("RampDownTime", ref originalValue); + __customData.rampDownTime = Mathf.Max(float.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("RampTime", originalValue, actionIndex)), 0); + + originalValue = string.Empty; + __instance.Properties.ParseString("RampDownSound", ref originalValue); + __customData.rampDownSound = _data.invData.itemValue.GetPropertyOverrideForAction("RampStartSound", originalValue, actionIndex); + + originalValue = 0.ToString(); + __instance.Properties.ParseString("PrepareTime", ref originalValue); + __customData.prepareTime = float.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("PrepareTime", originalValue, actionIndex)); + __customData.prepareSpeed = float.Parse(originalValue) / __customData.prepareTime; + + originalValue = string.Empty; + __instance.Properties.ParseString("PrepareSound", ref originalValue); + __customData.prepareSound = _data.invData.itemValue.GetPropertyOverrideForAction("PrepareSound", originalValue, actionIndex); + + originalValue = false.ToString(); + __instance.Properties.ParseString("PrepareOnAim", ref originalValue); + __customData.zoomPrepare = bool.Parse(_data.invData.itemValue.GetPropertyOverrideForAction("PrepareOnAim", originalValue, actionIndex)); + + originalValue = string.Empty; + __instance.Properties.ParseString("RampStableSound", ref originalValue); + __customData.rampStableSound = _data.invData.itemValue.GetPropertyOverrideForAction("RampStableSound", originalValue, actionIndex); + + __customData.totalChargeTime = __customData.prepareTime + __customData.rampUpTime; + __customData.rampDownTimeScale = __customData.rampDownTime > 0 ? (__customData.totalChargeTime) / __customData.rampDownTime : float.MaxValue; + + ResetAll(__customData, _data); + } + + [HarmonyPatch(nameof(ItemAction.StopHolding)), MethodTargetPostfix] + public void Postfix_StopHolding(RampUpData __customData, ItemActionData _data) + { + ResetAll(__customData, _data); + } + + [HarmonyPatch(nameof(ItemAction.ExecuteAction)), MethodTargetPrefix] + public bool Prefix_ExecuteAction(RampUpData __customData, ItemActionRanged __instance, ItemActionData _actionData, bool _bReleased) + { + ItemActionDataRanged rangedData = _actionData as ItemActionDataRanged; + if (!_bReleased && (__instance.InfiniteAmmo || _actionData.invData.itemValue.Meta > 0) && _actionData.invData.itemValue.PercentUsesLeft > 0) + { + rangedData.bReleased = false; + rangedData.bPressed = true; + if (__customData.curTime < __customData.prepareTime) + return false; + } + return true; + } + + private void UpdateTick(RampUpData data, ItemActionData actionData, bool isRampUp) + { + float previousTime = data.curTime; + float deltaTime = Time.time - data.lastTickTime; + data.lastTickTime = Time.time; + ref float curTime = ref data.curTime; + ref State curState = ref data.curState; + float totalChargeTime = data.totalChargeTime; + switch (curState) + { + case State.RampUp: + { + curTime = Mathf.Max(curTime, 0); + if (isRampUp) + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(prepareHash, true, true); + if (curTime < totalChargeTime) + { + curTime += deltaTime; + } + if (curTime >= data.prepareTime) + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(rampHash, true, true); + } + if (curTime >= totalChargeTime) + { + //Log.Out($"change state from {curState} to stable"); + actionData.invData.holdingEntity.PlayOneShot(data.rampStableSound); + curState = State.Stable; + } + } + else + { + //Log.Out($"change state from {curState} to ramp down"); + actionData.invData.holdingEntity.StopOneShot(data.rampUpSound); + actionData.invData.holdingEntity.PlayOneShot(data.rampDownSound); + curState = State.RampDown; + } + break; + } + case State.RampDown: + { + curTime = Mathf.Min(curTime, totalChargeTime); + if (!isRampUp) + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(rampHash, false, true); + if (curTime > 0) + { + curTime -= deltaTime * data.rampDownTimeScale; + } + if (curTime < data.prepareTime) + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(prepareHash, false, true); + } + if (curTime <= 0) + { + //Log.Out($"change state from {curState} to stable"); + //actionData.invData.holdingEntity.PlayOneShot(data.rampStableSound); + curState = State.Stable; + } + } + else + { + //Log.Out($"change state from {curState} to ramp up"); + actionData.invData.holdingEntity.StopOneShot(data.rampDownSound); + actionData.invData.holdingEntity.PlayOneShot(data.rampUpSound); + curState = State.RampUp; + } + break; + } + case State.Stable: + { + if (isRampUp) + { + if (curTime < totalChargeTime) + { + //Log.Out($"change state from {curState} to ramp up"); + actionData.invData.holdingEntity.StopOneShot(data.rampStableSound); + actionData.invData.holdingEntity.StopOneShot(data.rampDownSound); + actionData.invData.holdingEntity.PlayOneShot(data.rampUpSound); + curState = State.RampUp; + } + else + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(prepareHash, true, true); + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(rampHash, true, true); + } + } + else + { + if (curTime > 0) + { + //Log.Out($"change state from {curState} to ramp down"); + actionData.invData.holdingEntity.StopOneShot(data.rampStableSound); + actionData.invData.holdingEntity.StopOneShot(data.rampUpSound); + actionData.invData.holdingEntity.PlayOneShot(data.rampDownSound); + curState = State.RampDown; + } + else + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(prepareHash, false, true); + actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(rampHash, false, true); + } + } + break; + } + } + //Log.Out($"turret burst fire rate {turret.burstFireRate} max {turret.burstFireRateMax} cur time {curTime} cur state {curState} is ramp up {isRampUp} turret: ison {turret.IsOn} has target {turret.hasTarget} state {turret.state}"); + actionData.invData.holdingEntity.emodel.avatarController.UpdateFloat(prepareSpeedHash, data.prepareSpeed); + if (curTime != previousTime) + { + actionData.invData.holdingEntity.emodel.avatarController.UpdateFloat(prepareRatioHash, data.prepareRatio = (data.prepareTime == 0 ? 1f : Mathf.Clamp01(curTime / data.prepareTime))); + actionData.invData.holdingEntity.emodel.avatarController.UpdateFloat(rampRatioHash, data.rampRatio = (data.rampUpTime == 0 ? 1f : Mathf.Clamp01((curTime - data.prepareTime) / data.rampUpTime))); + actionData.invData.holdingEntity.emodel.avatarController.UpdateFloat(totalRatioHash, data.totalRatio = (totalChargeTime == 0 ? 1f : Mathf.Clamp01(curTime / totalChargeTime))); + } + } + + private void ResetAll(RampUpData _rampData, ItemActionData _actionData) + { + _rampData.curTime = 0f; + _rampData.lastTickTime = Time.time; + _rampData.curState = State.Stable; + _rampData.prepareRatio = 0f; + _rampData.rampRatio = 0f; + _rampData.totalRatio = 0f; + ((ItemActionDataRanged)_actionData).Delay = _rampData.originalDelay; + _actionData.invData.holdingEntity.StopOneShot(_rampData.prepareSound); + _actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(prepareHash, false, true); + _actionData.invData.holdingEntity.StopOneShot(_rampData.rampUpSound); + _actionData.invData.holdingEntity.emodel.avatarController.UpdateBool(rampHash, false, true); + //Log.Out("Reset all!"); + } + + public class RampUpData + { + public float maxMultiplier = 1f; + + public string prepareSound = string.Empty; + public float prepareSpeed = 1f; + public float prepareTime = 0f; + + public string rampUpSound = string.Empty; + public float rampUpTime = 0f; + public float totalChargeTime = 0f; + + public string rampDownSound = string.Empty; + public float rampDownTime = 0f; + public float rampDownTimeScale = float.MaxValue; + + public string rampStableSound = string.Empty; + + public float originalDelay = 0f; + public float curTime = 0f; + public State curState = State.Stable; + public float prepareRatio = 0f; + public float rampRatio = 0f; + public float totalRatio = 0f; + public float lastTickTime = 0f; + + public bool zoomPrepare = false; + + public ActionModuleRampUp rampUpModule; + + public RampUpData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleRampUp _module) + { + rampUpModule = _module; + } + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleTagged.cs b/Scripts/Items/ModularActions/ActionModuleTagged.cs new file mode 100644 index 0000000..b4a7dd8 --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleTagged.cs @@ -0,0 +1,30 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using KFCommonUtilityLib.Scripts.Utilities; +using UniLinq; + +[TypeTarget(typeof(ItemAction)), ActionDataTarget(typeof(TaggedData))] +public class ActionModuleTagged +{ + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationChanged(ItemAction __instance, ItemActionData _data, TaggedData __customData) + { + var tags = __instance.Properties.GetString("ActionTags").Split(',', System.StringSplitOptions.RemoveEmptyEntries); + var tags_to_add = _data.invData.itemValue.GetAllPropertyOverridesForAction("ActionTagsAppend", __instance.ActionIndex).SelectMany(s => s.Split(',', System.StringSplitOptions.RemoveEmptyEntries)); + var tags_to_remove = _data.invData.itemValue.GetAllPropertyOverridesForAction("ActionTagsRemove", __instance.ActionIndex).SelectMany(s => s.Split(',', System.StringSplitOptions.RemoveEmptyEntries)); + var tags_result = tags.Union(tags_to_add); + tags_result = tags_result.Except(tags_to_remove); + + __customData.tags = tags_result.Any() ? FastTags.Parse(string.Join(",", tags_result)) : FastTags.none; + //Log.Out($"tags: {string.Join(",", tags_result)}"); + } + + public class TaggedData + { + public FastTags tags; + public TaggedData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleTagged _module) + { + + } + } +} diff --git a/Scripts/Items/ModularActions/ActionModuleTranspilerTest.cs b/Scripts/Items/ModularActions/ActionModuleTranspilerTest.cs new file mode 100644 index 0000000..6a482fa --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleTranspilerTest.cs @@ -0,0 +1,48 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using System.Collections.Generic; +using System.Reflection.Emit; +using UnityEngine; + +[TypeTarget(typeof(ItemAction))] +public class ActionModuleTranspilerTest +{ + [HarmonyPatch(typeof(ItemActionAttack), nameof(ItemAction.ExecuteAction)), MethodTargetTranspiler] + private static IEnumerable Transpiler_InvalidTest(IEnumerable instructions) + { + yield return new CodeInstruction(OpCodes.Ldstr, "Ranged!"); + yield return CodeInstruction.Call(typeof(ActionModuleTranspilerTest), nameof(ActionModuleTranspilerTest.CallSomething)); + foreach (var ins in instructions) + { + yield return ins; + } + } + + + [HarmonyPatch(typeof(ItemActionRanged), nameof(ItemAction.ExecuteAction)), MethodTargetTranspiler] + private static IEnumerable Transpiler_RangedTest(IEnumerable instructions) + { + yield return new CodeInstruction(OpCodes.Ldstr, "Ranged!"); + yield return CodeInstruction.Call(typeof(ActionModuleTranspilerTest), nameof(ActionModuleTranspilerTest.CallSomething)); + foreach (var ins in instructions) + { + yield return ins; + } + } + + [HarmonyPatch(typeof(ItemActionCatapult), nameof(ItemAction.ExecuteAction)), MethodTargetTranspiler] + private static IEnumerable Transpiler_CatapultTest(IEnumerable instructions) + { + yield return new CodeInstruction(OpCodes.Ldstr, "Catapult!"); + yield return CodeInstruction.Call(typeof(ActionModuleTranspilerTest), nameof(ActionModuleTranspilerTest.CallSomething)); + foreach (var ins in instructions) + { + yield return ins; + } + } + + private static void CallSomething(string str) + { + Log.Out($"Call something: {str}\n{StackTraceUtility.ExtractStackTrace()}"); + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularActions/ActionModuleVariableZoom.cs b/Scripts/Items/ModularActions/ActionModuleVariableZoom.cs new file mode 100644 index 0000000..c423d09 --- /dev/null +++ b/Scripts/Items/ModularActions/ActionModuleVariableZoom.cs @@ -0,0 +1,260 @@ +using HarmonyLib; +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.Attributes; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; +using UnityEngine; + +[TypeTarget(typeof(ItemActionZoom)), ActionDataTarget(typeof(VariableZoomData))] +public class ActionModuleVariableZoom +{ + private const string METASAVENAME = "CurZoomStep"; + public static float zoomScale = 7.5f; + [HarmonyPatch(nameof(ItemAction.ConsumeScrollWheel)), MethodTargetPostfix] + private void Postfix_ConsumeScrollWheel(ItemActionData _actionData, float _scrollWheelInput, PlayerActionsLocal _playerInput, VariableZoomData __customData) + { + if (!_actionData.invData.holdingEntity.AimingGun || _scrollWheelInput == 0f) + { + return; + } + + ItemActionZoom.ItemActionDataZoom itemActionDataZoom = (ItemActionZoom.ItemActionDataZoom)_actionData; + if (!itemActionDataZoom.bZoomInProgress && !__customData.isToggleOnly) + { + __customData.curStep = Utils.FastClamp01(__customData.curStep + _scrollWheelInput); + __customData.stepSign = Mathf.Sign(_scrollWheelInput); + __customData.UpdateByStep(); + ItemValue scopeValue = __customData.ScopeValue; + if (scopeValue != null) + { + scopeValue.SetMetadata(METASAVENAME, __customData.SignedStep, TypedMetadataValue.TypeTag.Float); + _actionData.invData.holdingEntity.inventory.CallOnToolbeltChangedInternal(); + } + } + } + + [HarmonyPatch(nameof(ItemAction.OnModificationsChanged)), MethodTargetPostfix] + private void Postfix_OnModificationChanged(ItemActionZoom __instance, ItemActionData _data, VariableZoomData __customData) + { + string str = __instance.Properties.GetString("ZoomRatio"); + if (string.IsNullOrEmpty(str)) + { + str = "1"; + } + __customData.maxScale = StringParsers.ParseFloat(_data.invData.itemValue.GetPropertyOverride("ZoomRatio", str)); + + str = __instance.Properties.GetString("ZoomRatioMin"); + if (string.IsNullOrEmpty(str)) + { + str = __customData.maxScale.ToString(); + } + __customData.minScale = StringParsers.ParseFloat(_data.invData.itemValue.GetPropertyOverride("ZoomRatioMin", str)); + + str = _data.invData.itemValue.GetPropertyOverride("ToggleOnly", null); + if (!string.IsNullOrEmpty(str) && bool.TryParse(str, out __customData.isToggleOnly)) ; + + str = _data.invData.itemValue.GetPropertyOverride("ForceFovRange", null); + if (!string.IsNullOrEmpty(str) && StringParsers.TryParseRange(str, out __customData.fovRange) && __customData.fovRange.min > 0 && __customData.fovRange.max > 0) + { + __customData.fovRange = new FloatRange(Mathf.Min(__customData.fovRange.max, __customData.fovRange.min), Mathf.Max(__customData.fovRange.max, __customData.fovRange.min)); + __customData.forceFov = true; + } + + //__customData.maxFov = ScaleToFov(__customData.minScale); + //__customData.minFov = ScaleToFov(__customData.maxScale); + __customData.scopeValueIndex = _data.invData.itemValue.Modifications == null ? -1 : Array.FindIndex(_data.invData.itemValue.Modifications, static v => v?.ItemClass is IModuleContainerFor); + if (__customData.scopeValueIndex == -1 && _data.invData.itemValue.ItemClass is not IModuleContainerFor) + { + __customData.scopeValueIndex = int.MinValue; + } + ItemValue scopeValue = __customData.ScopeValue; + if (scopeValue != null) + { + if (scopeValue.GetMetadata(METASAVENAME) is float curStep) + { + __customData.curStep = Mathf.Abs(curStep); + __customData.stepSign = Mathf.Sign(curStep); + } + __customData.curStep = Utils.FastClamp01(__customData.curStep); + scopeValue.SetMetadata(METASAVENAME, __customData.SignedStep, TypedMetadataValue.TypeTag.Float); + _data.invData.holdingEntity.inventory.CallOnToolbeltChangedInternal(); + } + else + { + __customData.curStep = Utils.FastClamp01(__customData.curStep); + } + __customData.UpdateByStep(); + } + + //public static float FovToScale(float fov) + //{ + // return Mathf.Rad2Deg * 2 * Mathf.Atan(Mathf.Tan(Mathf.Deg2Rad * 27.5f) / fov); + //} + + //public static float ScaleToFov(float scale) + //{ + // return Mathf.Rad2Deg * 2 * Mathf.Atan(Mathf.Tan(Mathf.Deg2Rad * 27.5f) / scale); + //} + + //public static float GetNext(float cur) + //{ + // return Mathf.Sin(Mathf.PI * cur / 2); + //} + + public class VariableZoomData + { + public float maxScale = 1f; + public float minScale = 1f; + public float curScale = 0f; + //public float maxFov = 15f; + //public float minFov = 15f; + //public float curFov = 90f; + public bool forceFov = false; + public FloatRange fovRange = new FloatRange(15f, 15f); + public float curStep = 0; + public float stepSign = 1f; + public bool isToggleOnly = false; + public bool shouldUpdate = true; + public int scopeValueIndex = int.MinValue; + + public float SignedStep => curStep * stepSign; + public ItemValue ScopeValue + { + get + { + if (invData == null) + { + return null; + } + if (scopeValueIndex == -1) + { + return invData.itemValue; + } + else if (scopeValueIndex >= 0 && scopeValueIndex < invData.itemValue.Modifications.Length) + { + return invData.itemValue.Modifications[scopeValueIndex]; + } + return null; + } + } + public ItemInventoryData invData = null; + + public VariableZoomData(ItemInventoryData _invData, int _indexInEntityOfAction, ActionModuleVariableZoom _module) + { + invData = _invData; + } + + public void ToggleZoom() + { + //if (scopeValue != null && scopeValue.GetMetadata(METASAVENAME) is float curStep) + //{ + // this.curStep = Mathf.Abs(curStep); + // stepSign = MathF.Sign(curStep); + //} + if (stepSign > 0) + { + if (this.curStep >= 1) + { + this.curStep = 0; + } + else + { + this.curStep = 1; + } + } + else + { + if (this.curStep <= 0) + { + this.curStep = 1; + } + else + { + this.curStep = 0; + } + } + UpdateByStep(); + ItemValue scopeValue = ScopeValue; + if (scopeValue != null) + { + scopeValue.SetMetadata(METASAVENAME, SignedStep, TypedMetadataValue.TypeTag.Float); + invData.holdingEntity.inventory.CallOnToolbeltChangedInternal(); + } + } + + public void UpdateByStep() + { + //curFov = Utils.FastLerp(maxFov, minFov, GetNext(curStep)); + //curScale = FovToScale(curFov); + curScale = Utils.FastLerp(minScale, maxScale, curStep); + shouldUpdate = true; + } + } +} + +[HarmonyPatch] +public static class VariableZoomPatches +{ + [HarmonyPatch(typeof(PlayerMoveController), nameof(PlayerMoveController.Update))] + [HarmonyPrefix] + private static bool Prefix_Update_PlayerMoveController(PlayerMoveController __instance) + { + if (DroneManager.Debug_LocalControl || !__instance.gameManager.gameStateManager.IsGameStarted() || GameStats.GetInt(EnumGameStats.GameState) != 1) + return true; + + bool isUIOpen = __instance.windowManager.IsCursorWindowOpen() || __instance.windowManager.IsInputActive() || __instance.windowManager.IsModalWindowOpen(); + + UpdateLocalInput(__instance.entityPlayerLocal, isUIOpen); + + return true; + } + + private static void UpdateLocalInput(EntityPlayerLocal _player, bool _isUIOpen) + { + if (_isUIOpen || _player.emodel.IsRagdollActive || _player.IsDead() || _player.AttachedToEntity != null) + { + return; + } + + if (PlayerActionKFLib.Instance.Enabled && PlayerActionKFLib.Instance.ToggleZoom.WasPressed) + { + var actionData = _player.inventory.holdingItemData.actionData[1]; + if (actionData is IModuleContainerFor variableZoomData) + { + variableZoomData.Instance.ToggleZoom(); + } + } + } + + //[HarmonyPatch(typeof(Inventory), nameof(Inventory.SetItem), new Type[] { typeof(int), typeof(ItemValue), typeof(int), typeof(bool) })] + //[HarmonyTranspiler] + //private static IEnumerable Transpiler_Test(IEnumerable instructions) + //{ + // var codes = instructions.ToList(); + // var fld = AccessTools.Field(typeof(ItemStack), nameof(ItemStack.count)); + + // for (int i = 0; i < codes.Count; i++) + // { + // if (codes[i].StoresField(fld)) + // { + // codes.InsertRange(i + 1, new[] + // { + // new CodeInstruction(OpCodes.Ldloc_0), + // new CodeInstruction(OpCodes.Ldarg_0), + // new CodeInstruction(OpCodes.Ldarg_1), + // CodeInstruction.Call(typeof(VariableZoomPatches), nameof(LogMsg)) + // }); + // break; + // } + // } + // return codes; + //} + + //private static void LogMsg(bool flag, Inventory inv, int idx) + //{ + // if (inv.holdingItemIdx == idx) + // Log.Out($"changed: {flag}\n{StackTraceUtility.ExtractStackTrace()}"); + //} +} \ No newline at end of file diff --git a/Scripts/Items/ModularClasses/ItemModuleSortable.cs b/Scripts/Items/ModularClasses/ItemModuleSortable.cs new file mode 100644 index 0000000..9613cf7 --- /dev/null +++ b/Scripts/Items/ModularClasses/ItemModuleSortable.cs @@ -0,0 +1,87 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using System; +using System.Collections.Generic; + +[TypeTarget(typeof(ItemClassModifier))] +public class ItemModuleSortable +{ + //public int priority = int.MaxValue; + + //[HarmonyPatch(nameof(ItemClassModifier.Init)), MethodTargetPostfix] + //public void Postfix_Init(ItemClassModifier __instance) + //{ + // __instance.Properties.ParseInt("ModSortPriority", ref priority); + //} +} + +public struct ItemModuleSortableComparer : IComparer +{ + private string itemName; + public ItemModuleSortableComparer(ItemValue item) + { + itemName = item.ItemClass.Name; + } + + public int Compare(ItemValue x, ItemValue y) + { + return GetPriority(x) - GetPriority(y); + } + + private int GetPriority(ItemValue itemValue) + { + if (itemValue.ItemClass is ItemClassModifier modifierClass) + { + string str = null; + if (modifierClass.GetPropertyOverride("ModSortPriority", itemName, ref str) && int.TryParse(str, out int priority)) + { + return priority; + } + } + return int.MaxValue; + } +} + +[HarmonyPatch] +public static class ModSortingPatches +{ + //[HarmonyPatch(typeof(XUiC_ItemPartStackGrid), nameof(XUiC_ItemPartStackGrid.HandleSlotChangedEvent))] + //[HarmonyTranspiler] + //public static IEnumerable Transpiler_HandleSlotChangedEvent_XUiC_ItemPartStackGrid(IEnumerable instructions) + //{ + // var codes = instructions.ToList(); + // var prop_setstack = AccessTools.PropertySetter(typeof(XUiC_AssembleWindow), nameof(XUiC_AssembleWindow.ItemStack)); + // var idx = codes.FindIndex(x => x.Calls(prop_setstack)); + // if (idx > 0) + // { + // codes.InsertRange(idx, new[] + // { + // new CodeInstruction(OpCodes.Dup), + // new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(ModSortingPatches), nameof(SortMods))) + // }); + // } + // return codes; + //} + + //[HarmonyPatch(typeof(XUiC_ItemPartStackGrid), nameof(XUiC_ItemPartStackGrid.HandleSlotChangedEvent))] + //[HarmonyPostfix] + //private static void Postfix_HandleSlotChangedEvent_XUiC_ItemPartStackGrid(XUiC_ItemPartStackGrid __instance) + //{ + // __instance.SetParts(__instance.CurrentItem.itemValue?.Modifications); + //} + + [HarmonyPatch(typeof(XUiC_AssembleWindowGroup), nameof(XUiC_AssembleWindowGroup.ItemStack), MethodType.Setter)] + [HarmonyPrefix] + private static void Postfix_set_ItemStack_XUiC_AssembleWindowGroup(ItemStack value) + { + SortMods(value); + } + + private static void SortMods(ItemStack itemStack) + { + if (itemStack?.itemValue?.Modifications != null) + { + Array.Sort(itemStack.itemValue.Modifications, new ItemModuleSortableComparer(itemStack.itemValue)); + } + } +} \ No newline at end of file diff --git a/Scripts/Items/ModularClasses/ItemModuleVariableZoom.cs b/Scripts/Items/ModularClasses/ItemModuleVariableZoom.cs new file mode 100644 index 0000000..a6e5252 --- /dev/null +++ b/Scripts/Items/ModularClasses/ItemModuleVariableZoom.cs @@ -0,0 +1,6 @@ +using KFCommonUtilityLib.Scripts.Attributes; + +[TypeTarget(typeof(ItemClass))] +public class ItemModuleVariableZoom +{ +} \ No newline at end of file diff --git a/Scripts/MinEventActions/MinEventActionAddBuffToTargetAndSelf.cs b/Scripts/MinEventActions/MinEventActionAddBuffToTargetAndSelf.cs new file mode 100644 index 0000000..e7763dc --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionAddBuffToTargetAndSelf.cs @@ -0,0 +1,12 @@ +public class MinEventActionAddBuffToTargetAndSelf : MinEventActionAddBuff +{ + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + bool flag = base.CanExecute(_eventType, _params); + if (targetType == TargetTypes.selfAOE) + flag = true; + if (flag && targetType != TargetTypes.self) + targets.Add(_params.Self); + return flag; + } +} diff --git a/Scripts/MinEventActions/MinEventActionAddItemToInventory.cs b/Scripts/MinEventActions/MinEventActionAddItemToInventory.cs new file mode 100644 index 0000000..4a691cf --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionAddItemToInventory.cs @@ -0,0 +1,21 @@ +public class MinEventActionAddItemToInventory : MinEventActionItemAccessBase +{ + private ItemStack itemStackCache = new ItemStack(); + + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + if (itemValueCache == null) + { + itemValueCache = ItemClass.GetItem(itemName); + itemStackCache.itemValue = itemValueCache; + } + return !_params.Self.isEntityRemote && base.CanExecute(_eventType, _params); + } + + public override void Execute(MinEventParams _params) + { + itemStackCache.count = GetCount(_params); + _params.Self.TryStackItem(itemStackCache); + } +} + diff --git a/Scripts/MinEventActions/MinEventActionAddRoundsToInventory.cs b/Scripts/MinEventActions/MinEventActionAddRoundsToInventory.cs new file mode 100644 index 0000000..d6892a6 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionAddRoundsToInventory.cs @@ -0,0 +1,16 @@ +public class MinEventActionAddRoundsToInventory : MinEventActionAmmoAccessBase +{ + private ItemStack itemStackCache = new ItemStack(); + + public override void Execute(MinEventParams _params) + { + var _ranged = _params.ItemValue.ItemClass.Actions[_params.ItemActionData.indexInEntityOfAction] as ItemActionRanged; + string ammoName = _ranged.MagazineItemNames[_params.ItemValue.SelectedAmmoTypeIndex]; + if (!RoundsInInventory.TryGetValue(ammoName, out var ammoValue)) + return; + itemStackCache.itemValue = ammoValue; + itemStackCache.count = GetCount(_params); + _params.Self.TryStackItem(itemStackCache); + } +} + diff --git a/Scripts/MinEventActions/MinEventActionAddRoundsToMagazine.cs b/Scripts/MinEventActions/MinEventActionAddRoundsToMagazine.cs new file mode 100644 index 0000000..576b0ad --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionAddRoundsToMagazine.cs @@ -0,0 +1,28 @@ +using System.Xml.Linq; + +public class MinEventActionAddRoundsToMagazine : MinEventActionAmmoAccessBase +{ + private float maxPerc = -1; + public override void Execute(MinEventParams _params) + { + _params.ItemValue.Meta += GetCount(_params); + if (maxPerc > 0) + _params.ItemValue.Meta = Utils.FastMin((int)((_params.ItemValue.ItemClass.Actions[0] as ItemActionRanged).GetMaxAmmoCount(_params.ItemActionData) * maxPerc), _params.ItemValue.Meta); + _params.Self?.inventory?.CallOnToolbeltChangedInternal(); + } + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + if (base.ParseXmlAttribute(_attribute)) + return true; + + if (_attribute.Name.LocalName == "max") + { + maxPerc = float.Parse(_attribute.Value); + return true; + } + + return false; + } +} + diff --git a/Scripts/MinEventActions/MinEventActionAmmoAccessBase.cs b/Scripts/MinEventActions/MinEventActionAmmoAccessBase.cs new file mode 100644 index 0000000..51e4280 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionAmmoAccessBase.cs @@ -0,0 +1,56 @@ +using System.Xml.Linq; + +public class MinEventActionAmmoAccessBase : MinEventActionItemCountRandomBase +{ + private bool useMag = false; + private bool useRounds = false; + private bool revert = false; + private float perc = 1; + protected override int GetCount(MinEventParams _params) + { + if (!useMag || !(_params.ItemValue.ItemClass.Actions[_params.ItemActionData.indexInEntityOfAction] is ItemActionRanged _ranged)) + return base.GetCount(_params); + + if (!useRounds) + return (int)(_ranged.GetMaxAmmoCount(_params.ItemActionData) * perc); + + if (!revert) + return (int)((_params.ItemValue.Meta) * perc); + + return (int)((_ranged.GetMaxAmmoCount(_params.ItemActionData) - _params.ItemValue.Meta) * perc); + } + + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + return !_params.Self.isEntityRemote && base.CanExecute(_eventType, _params) && _params.ItemActionData is ItemActionRanged.ItemActionDataRanged && _params.ItemValue.ItemClass.Actions[_params.ItemActionData.indexInEntityOfAction] is ItemActionRanged; + } + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + if (base.ParseXmlAttribute(_attribute)) + return true; + + if (_attribute.Name.LocalName == "count" && _attribute.Value.Contains("MagazineSize")) + { + useMag = true; + string str = _attribute.Value; + if (str.StartsWith("%")) + { + useRounds = true; + str = str.Substring(1); + } + + if (str.StartsWith("!")) + { + revert = true; + str = str.Substring(1); + } + + string[] arr = str.Split(new char[] { '*' }, 2, System.StringSplitOptions.RemoveEmptyEntries); + if (arr.Length == 2) + return float.TryParse(arr[1], out perc); + return true; + } + return false; + } +} diff --git a/Scripts/MinEventActions/MinEventActionAttachPrefabToEntitySync.cs b/Scripts/MinEventActions/MinEventActionAttachPrefabToEntitySync.cs new file mode 100644 index 0000000..40c2136 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionAttachPrefabToEntitySync.cs @@ -0,0 +1,81 @@ +using KFCommonUtilityLib.Scripts.NetPackages; +using System.Collections.Generic; +using System.Xml.Linq; +using UnityEngine; + +public class MinEventActionAttachPrefabToEntitySync : MinEventActionAttachPrefabToEntity +{ + private static Dictionary dict_loaded = new Dictionary(); + //public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + //{ + // return base.CanExecute(_eventType, _params) && (_params.IsLocal || (_params.Self && !_params.Self.isEntityRemote)); + //} + + public override void Execute(MinEventParams _params) + { + base.Execute(_params); + if (ConnectionManager.Instance.IsServer) + { + ConnectionManager.Instance.SendPackage(NetPackageManager.GetPackage().Setup(_params.Self.entityId, prefab, parent_transform_path, local_offset, local_rotation, local_scale), false, -1, -1, _params.Self.entityId); + } + else if (_params.IsLocal || (_params.Self && !_params.Self.isEntityRemote)) + { + ConnectionManager.Instance.SendToServer(NetPackageManager.GetPackage().Setup(_params.Self.entityId, prefab, parent_transform_path, local_offset, local_rotation, local_scale)); + } + } + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + bool flag = false; + if (_attribute.Name.LocalName == "prefab") + { + prefab = _attribute.Value; + if (dict_loaded.TryGetValue(_attribute.Value, out GameObject go) && go) + { + goToInstantiate = go; + flag = true; + } + else + { + flag = base.ParseXmlAttribute(_attribute); + dict_loaded[_attribute.Value] = goToInstantiate; + } + } + else + { + flag = base.ParseXmlAttribute(_attribute); + } + return flag; + } + + public static void RemoteAttachPrefab(EntityAlive entity, string prefab, string path, Vector3 local_offset, Vector3 local_rotation, Vector3 local_scale) + { + Transform transform = entity.RootTransform; + if (!string.IsNullOrEmpty(path)) + { + transform = GameUtils.FindDeepChildActive(transform, path); + } + if (transform == null) + { + return; + } + GameObject goToInstantiate = dict_loaded[prefab]; + string text = "tempPrefab_" + goToInstantiate.name; + Transform transform2 = GameUtils.FindDeepChild(transform, text); + if (transform2 == null) + { + GameObject gameObject = UnityEngine.Object.Instantiate(goToInstantiate); + if (gameObject == null) + { + return; + } + transform2 = gameObject.transform; + gameObject.name = text; + Utils.SetLayerRecursively(gameObject, transform.gameObject.layer, null); + transform2.parent = transform; + transform2.localPosition = local_offset; + transform2.localRotation = Quaternion.Euler(local_rotation.x, local_rotation.y, local_rotation.z); + transform2.localScale = local_scale; + } + } +} diff --git a/Scripts/MinEventActions/MinEventActionBroadcastPlaySoundLocal.cs b/Scripts/MinEventActions/MinEventActionBroadcastPlaySoundLocal.cs new file mode 100644 index 0000000..e49cd69 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionBroadcastPlaySoundLocal.cs @@ -0,0 +1,8 @@ +public class MinEventActionBroadcastPlaySoundLocal : MinEventActionPlaySound +{ + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + return targetType == TargetTypes.self && !_params.Self.isEntityRemote && base.CanExecute(_eventType, _params); + } +} + diff --git a/Scripts/MinEventActions/MinEventActionCVarExpression.cs b/Scripts/MinEventActions/MinEventActionCVarExpression.cs new file mode 100644 index 0000000..569d809 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionCVarExpression.cs @@ -0,0 +1,248 @@ +using System; +using System.Collections.Generic; +using System.Xml.Linq; +using CodeWriter.ExpressionParser; +using UnityEngine; + +public class MinEventActionCVarExpression : MinEventActionTargetedBase +{ + private enum VariableType + { + None, + CVar, + RandomInt, + RandomFloat, + TierList + } + + private class VariableInfo + { + public VariableType varType; + public string cvarName; + public float[] valueList; + public float randomMin; + public float randomMax; + } + public string cvarName; + public MinEventActionModifyCVar.OperationTypes operation; + private bool isValid = false; + private ExpressionContext context; + private Expression compiledExpr; + private VariableInfo[] variableInfos; + private MinEventParams minEventContext; + private EntityAlive target; + + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + if (cvarName != null && cvarName.StartsWith("_")) + { + Log.Out("CVar '{0}' is readonly", new object[] { cvarName }); + return false; + } + if (!isValid) + { + Log.Out("Invalid expression!"); + return false; + } + return base.CanExecute(_eventType, _params); + } + + public override void Execute(MinEventParams _params) + { + if (_params.Self.isEntityRemote && !_params.IsLocal) + { + return; + } + minEventContext = _params; + if (compiledExpr == null) + { + return; + } + for (int i = 0; i < targets.Count; i++) + { + target = targets[i]; + float cvar = target.Buffs.GetCustomVar(cvarName); + float value = compiledExpr.Invoke(); + switch (operation) + { + case MinEventActionModifyCVar.OperationTypes.set: + case MinEventActionModifyCVar.OperationTypes.setvalue: + cvar = value; + break; + case MinEventActionModifyCVar.OperationTypes.add: + cvar += value; + break; + case MinEventActionModifyCVar.OperationTypes.subtract: + cvar -= value; + break; + case MinEventActionModifyCVar.OperationTypes.multiply: + cvar *= value; + break; + case MinEventActionModifyCVar.OperationTypes.divide: + cvar /= ((value == 0f) ? 0.0001f : value); + break; + case MinEventActionModifyCVar.OperationTypes.percentadd: + cvar += cvar * value; + break; + case MinEventActionModifyCVar.OperationTypes.percentsubtract: + cvar -= cvar * value; + break; + } + target.Buffs.SetCustomVar(cvarName, cvar); + } + minEventContext = null; + target = null; + } + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + bool flag = base.ParseXmlAttribute(_attribute); + if (!flag) + { + switch(_attribute.Name.LocalName) + { + case "cvar": + cvarName = _attribute.Value; + flag = true; + break; + case "expression": + isValid = true; + string expr = _attribute.Value; + context = new ExpressionContext(); + List variableInfos = new List(); + Dictionary varStrs = new Dictionary(); + while (true) + { + int nextVarStart = expr.IndexOf('['); + if (nextVarStart < 0) + { + break; + } + int nextVarEnd = expr.IndexOf(']', nextVarStart); + if (nextVarEnd < 0) + { + isValid = false; + break; + } + string varStr = expr.Substring(nextVarStart + 1, nextVarEnd - nextVarStart - 1); + VariableInfo variableInfo = null; + if (varStr.StartsWith("@")) + { + if (!varStrs.ContainsKey(varStr)) + { + variableInfo = new VariableInfo(); + variableInfo.varType = VariableType.CVar; + variableInfo.cvarName = varStr.Substring(1); + varStrs.Add(varStr, variableInfos.Count); + } + } + else if (varStr.StartsWith("randomInt", StringComparison.OrdinalIgnoreCase)) + { + variableInfo = new VariableInfo(); + variableInfo.varType = VariableType.RandomInt; + Vector2 vector = StringParsers.ParseVector2(varStr.Substring(varStr.IndexOf('(') + 1, varStr.IndexOf(')') - (varStr.IndexOf('(') + 1))); + variableInfo.randomMin = (int)vector.x; + variableInfo.randomMax = (int)vector.y; + } + else if (varStr.StartsWith("randomFloat", StringComparison.OrdinalIgnoreCase)) + { + variableInfo = new VariableInfo(); + variableInfo.varType = VariableType.RandomFloat; + Vector2 vector = StringParsers.ParseVector2(varStr.Substring(varStr.IndexOf('(') + 1, varStr.IndexOf(')') - (varStr.IndexOf('(') + 1))); + variableInfo.randomMin = vector.x; + variableInfo.randomMax = vector.y; + } + else if (varStr.Contains(',')) + { + if (!varStrs.ContainsKey(varStr)) + { + variableInfo = new VariableInfo(); + variableInfo.varType = VariableType.TierList; + string[] array = varStr.Split(',', StringSplitOptions.None); + variableInfo.valueList = new float[array.Length]; + for (int i = 0; i < array.Length; i++) + { + variableInfo.valueList[i] = float.Parse(array[i]); + } + varStrs.Add(varStr, variableInfos.Count); + } + } + else if (float.TryParse(varStr, out _)) + { + + expr = expr.Remove(nextVarEnd).Remove(nextVarStart); + } + else + { + isValid = false; + break; + } + int curIndex = varStrs.TryGetValue(varStr, out var index) ? index : variableInfos.Count; + string varName = "x" + curIndex; + expr = expr.Remove(nextVarStart, nextVarEnd - nextVarStart + 1).Insert(nextVarStart, varName); + //Log.Out($"cur index {curIndex} var name {varStr} is new var {curIndex == variableInfos.Count}"); + if (curIndex == variableInfos.Count) + { + context.RegisterVariable(varName, () => { return EvaluateVar(curIndex); }); + } + if (variableInfo != null) + { + variableInfos.Add(variableInfo); + } + } + if (!isValid) + { + Log.Out("Invalid expression: {0}", new object[] { expr }); + return false; + } + Log.Out($"Compiling expr {expr}..."); + compiledExpr = FloatExpressionParser.Instance.Compile(expr, context, true); + this.variableInfos = variableInfos.ToArray(); + flag = true; + break; + case "operation": + this.operation = EnumUtils.Parse(_attribute.Value, true); + flag = true; + break; + } + } + return flag; + } + + private float EvaluateVar(int index) + { + var variableInfo = variableInfos[index]; + switch (variableInfo.varType) + { + case VariableType.CVar: + return target.Buffs.GetCustomVar(variableInfo.cvarName); + case VariableType.RandomInt: + return Mathf.Clamp(minEventContext.Self.rand.RandomRange((int)variableInfo.randomMin, (int)variableInfo.randomMax + 1), variableInfo.randomMin, variableInfo.randomMax); + case VariableType.RandomFloat: + return Mathf.Clamp(minEventContext.Self.rand.RandomRange(variableInfo.randomMin, variableInfo.randomMax + 1), variableInfo.randomMin, variableInfo.randomMax); + case VariableType.TierList: + if (minEventContext.ParentType == MinEffectController.SourceParentType.ItemClass || minEventContext.ParentType == MinEffectController.SourceParentType.ItemModifierClass) + { + if (!minEventContext.ItemValue.IsEmpty()) + { + int tier = (int)(minEventContext.ItemValue.Quality - 1); + if (tier >= 0) + { + return variableInfo.valueList[tier]; + } + } + } + else if (minEventContext.ParentType == MinEffectController.SourceParentType.ProgressionClass && minEventContext.ProgressionValue != null) + { + int level = minEventContext.ProgressionValue.CalculatedLevel(minEventContext.Self); + if (level >= 0) + { + return variableInfo.valueList[level]; + } + } + return 0f; + default: + return 0f; + } + } +} \ No newline at end of file diff --git a/Scripts/MinEventActions/MinEventActionDecreaseProgressionLevelAndRefundSP.cs b/Scripts/MinEventActions/MinEventActionDecreaseProgressionLevelAndRefundSP.cs new file mode 100644 index 0000000..8668770 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionDecreaseProgressionLevelAndRefundSP.cs @@ -0,0 +1,25 @@ +public class MinEventActionDecreaseProgressionLevelAndRefundSP : MinEventActionSetProgressionLevel +{ + public override void Execute(MinEventParams _params) + { + EntityPlayerLocal entityPlayerLocal = this.targets[0] as EntityPlayerLocal; + if (this.targets != null) + { + ProgressionValue progressionValue = entityPlayerLocal.Progression.GetProgressionValue(this.progressionName); + if (progressionValue != null) + { + if (this.level >= 0 && this.level < progressionValue.Level) + { + ProgressionClass progressionClass = progressionValue.ProgressionClass; + int spcount = 0; + for (int i = this.level + 1; i <= progressionValue.Level; i++) + spcount += progressionClass.CalculatedCostForLevel(i); + progressionValue.Level = this.level; + entityPlayerLocal.Progression.SkillPoints += spcount; + entityPlayerLocal.Progression.bProgressionStatsChanged = true; + entityPlayerLocal.bPlayerStatsChanged = true; + } + } + } + } +} diff --git a/Scripts/MinEventActions/MinEventActionItemAccessBase.cs b/Scripts/MinEventActions/MinEventActionItemAccessBase.cs new file mode 100644 index 0000000..7324526 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionItemAccessBase.cs @@ -0,0 +1,23 @@ +using System.Xml.Linq; + +public class MinEventActionItemAccessBase : MinEventActionItemCountRandomBase +{ + protected string itemName; + protected ItemValue itemValueCache = null; + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + if (base.ParseXmlAttribute(_attribute)) + return true; + + switch (_attribute.Name.LocalName) + { + case "item": + itemName = _attribute.Value; + return true; + default: + return false; + } + } +} + diff --git a/Scripts/MinEventActions/MinEventActionItemCountRandomBase.cs b/Scripts/MinEventActions/MinEventActionItemCountRandomBase.cs new file mode 100644 index 0000000..638d373 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionItemCountRandomBase.cs @@ -0,0 +1,60 @@ +using System.Xml.Linq; +using UnityEngine; +public class MinEventActionItemCountRandomBase : MinEventActionBase +{ + private bool useRange = false; + private bool useRandom = false; + private bool useCvar = false; + private int[] random; + private Vector2i range; + private string cvarRef; + private int constant; + + protected virtual int GetCount(MinEventParams _params) + { + if (useRandom) + return random[Random.Range(0, random.Length)]; + else if (useRange) + return Random.Range(range.x, range.y + 1); + else if (useCvar) + return (int)_params.Self.GetCVar(cvarRef); + else + return constant; + } + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + if (base.ParseXmlAttribute(_attribute)) + return true; + + switch (_attribute.Name.LocalName) + { + case "count": + string str = _attribute.Value; + if (str.StartsWith("random")) + { + useRandom = true; + string[] values = str.Substring(str.IndexOf('(') + 1, str.IndexOf(')') - str.IndexOf('(') - 1).Split(','); + random = new int[values.Length]; + for (int i = 0; i < values.Length; i++) + random[i] = int.Parse(values[i]); + } + else if (str.StartsWith("range")) + { + useRange = true; + range = StringParsers.ParseVector2i(str.Substring(str.IndexOf('(') + 1, str.IndexOf(')') - str.IndexOf('(') - 1)); + } + else if (str.StartsWith("@")) + { + useCvar = true; + cvarRef = str.Substring(1); + } + else + return int.TryParse(str, out constant); + + return true; + default: + return false; + } + } +} diff --git a/Scripts/MinEventActions/MinEventActionModifyCVarWithLocalCache.cs b/Scripts/MinEventActions/MinEventActionModifyCVarWithLocalCache.cs new file mode 100644 index 0000000..ad07d45 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionModifyCVarWithLocalCache.cs @@ -0,0 +1,72 @@ +using KFCommonUtilityLib; +using System.Xml.Linq; + +public class MinEventActionModifyCVarWithLocalCache : MinEventActionModifyCVar +{ + int targetHash; + private int actionIndex = -1; + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + bool flag = !_params.Self.isEntityRemote && (actionIndex < 0 ? _params.ItemActionData : _params.ItemActionData.invData.actionData[actionIndex]) is IModuleContainerFor && base.CanExecute(_eventType, _params); + //Log.Out($"can execute {flag} is remote {_params.Self.isEntityRemote} action index {actionIndex} cache {targetHash.ToString()} action {(actionIndex < 0 ? _params.ItemActionData : _params.ItemActionData.invData.actionData[actionIndex]).GetType().Name}"); + return flag; + } + + public override void Execute(MinEventParams _params) + { + if (_params.Self.isEntityRemote && !_params.IsLocal) + { + return; + } + ActionModuleLocalPassiveCache.LocalPassiveCacheData _data = ((IModuleContainerFor)(actionIndex < 0 ? _params.ItemActionData : _params.ItemActionData.invData.actionData[actionIndex])).Instance; + float value = _data.GetCachedValue(targetHash); + //Log.Out($"cache {targetHash.ToString()} value {value}"); + for (int i = 0; i < targets.Count; i++) + { + float num = targets[i].Buffs.GetCustomVar(cvarName); + switch (operation) + { + case OperationTypes.set: + case OperationTypes.setvalue: + num = value; + break; + case OperationTypes.add: + num += value; + break; + case OperationTypes.subtract: + num -= value; + break; + case OperationTypes.multiply: + num *= value; + break; + case OperationTypes.divide: + num /= ((value == 0f) ? 0.0001f : value); + break; + } + targets[i].Buffs.SetCustomVar(cvarName, num, (targets[i].isEntityRemote && !_params.Self.isEntityRemote) || _params.IsLocal); + } + } + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + bool flag = false; + string name = _attribute.Name.LocalName; + if (name != null) + { + if (name == "cache") + { + targetHash = _attribute.Value.GetHashCode(); + flag = true; + } + else if (name == "action_index") + { + actionIndex = int.Parse(_attribute.Value); + flag = true; + } + } + + if (!flag) + flag = base.ParseXmlAttribute(_attribute); + return flag; + } +} \ No newline at end of file diff --git a/Scripts/MinEventActions/MinEventActionModifyCVarWithSelfRef.cs b/Scripts/MinEventActions/MinEventActionModifyCVarWithSelfRef.cs new file mode 100644 index 0000000..72a9ebc --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionModifyCVarWithSelfRef.cs @@ -0,0 +1,48 @@ +using System.Xml.Linq; + +class MinEventActionModifyCVarWithSelfRef : MinEventActionModifyCVar +{ + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + return base.CanExecute(_eventType, _params); + } + + public override void Execute(MinEventParams _params) + { + if (cvarRef) + { + if (_params.Self.isEntityRemote && !_params.IsLocal) + { + return; + } + value = _params.Self.Buffs.GetCustomVar(refCvarName); + for (int i = 0; i < targets.Count; i++) + { + float num = targets[i].Buffs.GetCustomVar(cvarName); + switch (operation) + { + case OperationTypes.set: + case OperationTypes.setvalue: + num = value; + break; + case OperationTypes.add: + num += value; + break; + case OperationTypes.subtract: + num -= value; + break; + case OperationTypes.multiply: + num *= value; + break; + case OperationTypes.divide: + num /= ((value == 0f) ? 0.0001f : value); + break; + } + targets[i].Buffs.SetCustomVar(cvarName, num, (targets[i].isEntityRemote && !_params.Self.isEntityRemote) || _params.IsLocal); + } + } + else + base.Execute(_params); + } +} + diff --git a/Scripts/MinEventActions/MinEventActionOverrideZoomFOV.cs b/Scripts/MinEventActions/MinEventActionOverrideZoomFOV.cs new file mode 100644 index 0000000..d43f4d8 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionOverrideZoomFOV.cs @@ -0,0 +1,101 @@ +using HarmonyLib; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Xml.Linq; +using UnityEngine; + +public class MinEventActionOverrideZoomFOV : MinEventActionBase +{ + private int fov = 0; + //private static Type zoomDataType = typeof(ItemActionZoom).GetNestedType("ItemActionDataZoom", System.Reflection.BindingFlags.NonPublic); + //private static FieldInfo fldZoomInProgress = AccessTools.Field(zoomDataType, "bZoomInProgress"); + //private static FieldInfo fldTimeZoomStarted = AccessTools.Field(zoomDataType, "timeZoomStarted"); + //private static FieldInfo fldCurrentZoom = AccessTools.Field(zoomDataType, "CurrentZoom"); + //private static FieldInfo fldMaxZoomOut = AccessTools.Field(zoomDataType, "MaxZoomOut"); + //private static FieldInfo fldMaxZoomIn = AccessTools.Field(zoomDataType, "MaxZoomIn"); + //private static FieldInfo fldEndLerpFov = AccessTools.Field(typeof(EntityPlayerLocal), "lerpCameraEndFOV"); + //private static MethodInfo mtdUpdateCameraPosition = AccessTools.Method(typeof(EntityAlive), "updateCameraPosition"); + + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + if (!base.CanExecute(_eventType, _params)) + return false; + + return _params.Self is EntityPlayerLocal player && player?.inventory != null && player.inventory.holdingItemData?.actionData[1] is ItemActionZoom.ItemActionDataZoom; + } + + public override void Execute(MinEventParams _params) + { + base.Execute(_params); + var target = (EntityPlayerLocal)_params.Self; + var zoomActionData = (ItemActionZoom.ItemActionDataZoom)target.inventory.holdingItemData.actionData[1]; + int targetFov = fov; + int targetMax = fov; + int targetMin = fov; + //restore min max fov + if (fov <= 0) + { + float fovSetting = (float)GamePrefs.GetInt(EnumGamePrefs.OptionsGfxFOV); + ItemAction action = target.inventory.holdingItem.Actions[1]; + if (action.Properties != null && action.Properties.Values.ContainsKey("Zoom_max_out")) + { + targetMax = StringParsers.ParseSInt32(target.inventory.holdingItemData.itemValue.GetPropertyOverride("Zoom_max_out", action.Properties.Values["Zoom_max_out"]), 0, -1, NumberStyles.Integer); + } + else + { + targetMax = StringParsers.ParseSInt32(target.inventory.holdingItemData.itemValue.GetPropertyOverride("Zoom_max_out", fovSetting.ToString()), 0, -1, NumberStyles.Integer); + } + if (action.Properties != null && action.Properties.Values.ContainsKey("Zoom_max_in")) + { + targetMin = StringParsers.ParseSInt32(target.inventory.holdingItemData.itemValue.GetPropertyOverride("Zoom_max_in", action.Properties.Values["Zoom_max_in"]), 0, -1, NumberStyles.Integer); + } + else + { + targetMin = StringParsers.ParseSInt32(target.inventory.holdingItemData.itemValue.GetPropertyOverride("Zoom_max_in", fovSetting.ToString()), 0, -1, NumberStyles.Integer); + } + targetFov = targetMax; + } + + zoomActionData.MaxZoomIn = targetMin; + zoomActionData.MaxZoomOut = targetMax; + zoomActionData.CurrentZoom = targetFov; + //Log.Out($"setting zoom override max {targetMax} min {targetMin} cur {targetFov}"); + //if is aiming, lerp towards the final result + if (target.AimingGun) + { + //if lerp not in progress, start lerp + if (!target.bLerpCameraFlag) + { + zoomActionData.bZoomInProgress = true; + zoomActionData.timeZoomStarted = Time.time; + target.updateCameraPosition(true); + } + //if already in progress, set end value + else + { + target.lerpCameraEndFOV = targetFov; + } + + //Log.Out($"begin lerp camera"); + } + } + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + if(base.ParseXmlAttribute(_attribute)) + return true; + + switch(_attribute.Name.LocalName) + { + case "value": + fov = StringParsers.ParseSInt32(_attribute.Value); + return true; + } + return false; + } +} diff --git a/Scripts/MinEventActions/MinEventActionRemoteHoldingBase.cs b/Scripts/MinEventActions/MinEventActionRemoteHoldingBase.cs new file mode 100644 index 0000000..42adc45 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionRemoteHoldingBase.cs @@ -0,0 +1,31 @@ +//workaround for inventory sync +//full toolbelt data is sent when holding item value changed or whatever, after a certain delay +//causing remote players to update current holding item constantly +//thus we need to handle some holding event for remote players on local player side +using System.Xml.Linq; + +public class MinEventActionRemoteHoldingBase : MinEventActionBase +{ + protected bool isRemoteHolding = false; + protected bool localOnly = true; + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + if (base.ParseXmlAttribute(_attribute)) + return true; + + if (_attribute.Name == "local_only") + { + localOnly = bool.Parse(_attribute.Value); + return true; + } + return false; + } + + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + isRemoteHolding = (_eventType == MinEventTypes.onSelfEquipStart && _params.Self.isEntityRemote); + return (!localOnly || !_params.Self.isEntityRemote) && (!_params.Self.isEntityRemote || isRemoteHolding) && base.CanExecute(_eventType, _params); + } +} + diff --git a/Scripts/MinEventActions/MinEventActionRemoveItemFromInventory.cs b/Scripts/MinEventActions/MinEventActionRemoveItemFromInventory.cs new file mode 100644 index 0000000..886f3c0 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionRemoveItemFromInventory.cs @@ -0,0 +1,15 @@ +public class MinEventActionRemoveItemFromInventory : MinEventActionItemAccessBase +{ + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + if (itemValueCache == null) + itemValueCache = ItemClass.GetItem(itemName); + return !_params.Self.isEntityRemote && base.CanExecute(_eventType, _params); + } + + public override void Execute(MinEventParams _params) + { + _params.Self.TryRemoveItem(GetCount(_params), itemValueCache); + } +} + diff --git a/Scripts/MinEventActions/MinEventActionRemovePrefabFromHeldItem.cs b/Scripts/MinEventActions/MinEventActionRemovePrefabFromHeldItem.cs new file mode 100644 index 0000000..eb42d14 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionRemovePrefabFromHeldItem.cs @@ -0,0 +1,46 @@ +using KFCommonUtilityLib.Scripts.StaticManagers; +using UnityEngine; + +public class MinEventActionRemovePrefabFromHeldItem : MinEventActionRemovePrefabFromEntity +{ + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + return base.CanExecute(_eventType, _params) && _params.Transform; + } + + public override void Execute(MinEventParams _params) + { + if (!_params.Self) + { + return; + } + + Transform parent = AnimationRiggingManager.GetAddPartTransformOverride(_params.Transform, parent_transform_path, false); + if (parent) + { + Transform child = null; + string prefabName = "tempPrefab_" + base.prefabName; + if (_params.Transform.TryGetComponent(out var targets)) + { + GameObject prefab = targets.GetPrefab(prefabName); + if (prefab) + { + child = prefab.transform; + } + } + if (!child) + { + child = parent.Find(prefabName); + } + if (child) + { + if (child.TryGetComponent(out var reference)) + { + reference.Remove(); + } + child.parent = null; + GameObject.Destroy(child.gameObject); + } + } + } +} \ No newline at end of file diff --git a/Scripts/MinEventActions/MinEventActionRemoveRoundsFromInventory.cs b/Scripts/MinEventActions/MinEventActionRemoveRoundsFromInventory.cs new file mode 100644 index 0000000..a3ea44e --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionRemoveRoundsFromInventory.cs @@ -0,0 +1,19 @@ +public class MinEventActionRemoveRoundsFromInventory : MinEventActionAmmoAccessBase +{ + private ItemValue itemValueCache; + + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + if (!base.CanExecute(_eventType, _params)) + return false; + + var _ranged = _params.ItemValue.ItemClass.Actions[_params.ItemActionData.indexInEntityOfAction] as ItemActionRanged; + string ammoName = _ranged.MagazineItemNames[_params.ItemValue.SelectedAmmoTypeIndex]; + return RoundsInInventory.TryGetValue(ammoName, out itemValueCache); + } + public override void Execute(MinEventParams _params) + { + _params.Self.TryRemoveItem(GetCount(_params), itemValueCache); + } +} + diff --git a/Scripts/MinEventActions/MinEventActionSetAmmoOnWeaponLabel.cs b/Scripts/MinEventActions/MinEventActionSetAmmoOnWeaponLabel.cs new file mode 100644 index 0000000..0045357 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionSetAmmoOnWeaponLabel.cs @@ -0,0 +1,64 @@ +using System.Xml.Linq; + +public class MinEventActionSetAmmoOnWeaponLabel : MinEventActionRemoteHoldingBase +{ + private int slot = 0; + private bool maxAmmo = false; + private bool useHoldingItemValue = false; + private string[] wrap; + private bool usePattern = false; + public override bool ParseXmlAttribute(XAttribute _attribute) + { + bool flag = base.ParseXmlAttribute(_attribute); + if (!flag) + { + flag = true; + string name = _attribute.Name.LocalName; + switch (name) + { + case "slot": + slot = int.Parse(_attribute.Value); + break; + case "pattern": + string str = _attribute.Value; + wrap = str.Split(new string[] { "[ammo]" }, System.StringSplitOptions.None); + usePattern = true; + break; + case "max_ammo": + maxAmmo = bool.Parse(_attribute.Value); + break; + default: + flag = false; + break; + } + } + + return flag; + } + + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + //somehow when onSelfEquipStart is fired, holding item value is not successfully updated in MinEventParams + useHoldingItemValue = _eventType == MinEventTypes.onSelfEquipStart; + //consume_ammo = _eventType == MinEventTypes.onSelfRangedBurstShot; + return base.CanExecute(_eventType, _params); + } + + public override void Execute(MinEventParams _params) + { + int meta; + var inv = _params.Self.inventory; + var value = useHoldingItemValue ? inv.holdingItemItemValue : _params.ItemValue; + if (!maxAmmo) + meta = value.Meta; + else + meta = (int)EffectManager.GetValue(PassiveEffects.MagazineSize, value, inv.GetHoldingGun().BulletsPerMagazine, _params.Self); + string str = usePattern ? string.Join(meta.ToString(), wrap) : meta.ToString(); + //int num = consume_ammo ? meta - 1 : meta; + if (isRemoteHolding || localOnly) + NetPackageSyncWeaponLabelText.SetWeaponLabelText(_params.Self, slot, str); + else if (!_params.Self.isEntityRemote) + NetPackageSyncWeaponLabelText.NetSyncSetWeaponLabelText(_params.Self, slot, str); + } +} + diff --git a/Scripts/MinEventActions/MinEventActionSetMetadataOnWeaponLabel.cs b/Scripts/MinEventActions/MinEventActionSetMetadataOnWeaponLabel.cs new file mode 100644 index 0000000..97e1123 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionSetMetadataOnWeaponLabel.cs @@ -0,0 +1,64 @@ +using System.Xml.Linq; + +public class MinEventActionSetMetadataOnWeaponLabel : MinEventActionRemoteHoldingBase +{ + private int slot = 0; + private bool useHoldingItemValue = false; + private string[] wrap; + private bool usePattern = false; + private string metadata; + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + bool flag = base.ParseXmlAttribute(_attribute); + if (!flag) + { + flag = true; + string name = _attribute.Name.LocalName; + switch (name) + { + case "slot": + slot = int.Parse(_attribute.Value); + break; + case "pattern": + string str = _attribute.Value; + wrap = str.Split(new string[] { "[metadata]" }, System.StringSplitOptions.None); + usePattern = true; + break; + case "metadata": + metadata = _attribute.Value; + break; + default: + flag = false; + break; + } + } + + return flag; + } + + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + //somehow when onSelfEquipStart is fired, holding item value is not successfully updated in MinEventParams + useHoldingItemValue = _eventType == MinEventTypes.onSelfEquipStart; + //consume_ammo = _eventType == MinEventTypes.onSelfRangedBurstShot; + return !string.IsNullOrEmpty(metadata) && base.CanExecute(_eventType, _params); + } + + public override void Execute(MinEventParams _params) + { + var inv = _params.Self.inventory; + var value = useHoldingItemValue ? inv.holdingItemItemValue : _params.ItemValue; + object obj = value.GetMetadata(metadata); + if (obj is false || obj is null) + { + return; + } + string meta = obj.ToString(); + string str = usePattern ? string.Join(meta.ToString(), wrap) : meta.ToString(); + if (isRemoteHolding || localOnly) + NetPackageSyncWeaponLabelText.SetWeaponLabelText(_params.Self, slot, str); + else if (!_params.Self.isEntityRemote) + NetPackageSyncWeaponLabelText.NetSyncSetWeaponLabelText(_params.Self, slot, str); + } +} \ No newline at end of file diff --git a/Scripts/MinEventActions/MinEventActionSetPassiveOnWeaponLabel.cs b/Scripts/MinEventActions/MinEventActionSetPassiveOnWeaponLabel.cs new file mode 100644 index 0000000..1027da0 --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionSetPassiveOnWeaponLabel.cs @@ -0,0 +1,64 @@ +using KFCommonUtilityLib.Scripts.StaticManagers; +using System.Xml.Linq; + +public class MinEventActionSetPassiveOnWeaponLabel : MinEventActionRemoteHoldingBase +{ + private int slot = 0; + private bool useHoldingItemValue = false; + private string[] wrap; + private bool usePattern = false; + private PassiveEffects passive; + private FastTags tags; + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + bool flag = base.ParseXmlAttribute(_attribute); + if (!flag) + { + flag = true; + string name = _attribute.Name.LocalName; + switch (name) + { + case "slot": + slot = int.Parse(_attribute.Value); + break; + case "pattern": + string str = _attribute.Value; + wrap = str.Split(new string[] { "[passive]" }, System.StringSplitOptions.None); + usePattern = true; + break; + case "passive": + passive = CustomEffectEnumManager.RegisterOrGetEnum(_attribute.Value, true); + break; + case "tags": + tags = FastTags.Parse(_attribute.Value); + break; + default: + flag = false; + break; + } + } + + return flag; + } + + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + //somehow when onSelfEquipStart is fired, holding item value is not successfully updated in MinEventParams + useHoldingItemValue = _eventType == MinEventTypes.onSelfEquipStart; + //consume_ammo = _eventType == MinEventTypes.onSelfRangedBurstShot; + return base.CanExecute(_eventType, _params); + } + + public override void Execute(MinEventParams _params) + { + var inv = _params.Self.inventory; + var value = useHoldingItemValue ? inv.holdingItemItemValue : _params.ItemValue; + float res = EffectManager.GetValue(passive, value, 0, _params.Self, null, tags); + string str = usePattern ? string.Join(res.ToString(), wrap) : res.ToString(); + if (isRemoteHolding || localOnly) + NetPackageSyncWeaponLabelText.SetWeaponLabelText(_params.Self, slot, str); + else if (!_params.Self.isEntityRemote) + NetPackageSyncWeaponLabelText.NetSyncSetWeaponLabelText(_params.Self, slot, str); + } +} \ No newline at end of file diff --git a/Scripts/MinEventActions/MinEventActionSetStringOnWeaponLabel.cs b/Scripts/MinEventActions/MinEventActionSetStringOnWeaponLabel.cs new file mode 100644 index 0000000..8b8478a --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionSetStringOnWeaponLabel.cs @@ -0,0 +1,59 @@ +using System.Xml.Linq; + +public class MinEventActionSetStringOnWeaponLabel : MinEventActionRemoteHoldingBase +{ + private int slot = 0; + private string text; + private bool isCvar = false; + private bool isMetadata = false; + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + bool flag = base.ParseXmlAttribute(_attribute); + if (!flag) + { + flag = true; + string name = _attribute.Name.LocalName; + switch (name) + { + case "slot": + slot = int.Parse(_attribute.Value); + break; + case "text": + text = _attribute.Value; + break; + case "cvar": + text = _attribute.Value; + isCvar = true; + isMetadata = false; + break; + case "metadata": + text = _attribute.Value; + isMetadata = true; + isCvar = false; + break; + default: + flag = false; + break; + } + } + + return flag; + } + + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + if (isMetadata && (_params.ItemValue == null || !_params.ItemValue.HasMetadata(text))) + return false; + return base.CanExecute(_eventType, _params); + } + + public override void Execute(MinEventParams _params) + { + if (isRemoteHolding || localOnly) + NetPackageSyncWeaponLabelText.SetWeaponLabelText(_params.Self, slot, isCvar ? _params.Self.GetCVar(text).ToString() : (isMetadata ? _params.ItemValue.GetMetadata(text).ToString() : text)); + else if (!_params.Self.isEntityRemote) + NetPackageSyncWeaponLabelText.NetSyncSetWeaponLabelText(_params.Self, slot, isCvar ? _params.Self.GetCVar(text).ToString() : (isMetadata ? _params.ItemValue.GetMetadata(text).ToString() : text)); + } +} + diff --git a/Scripts/MinEventActions/MinEventActionSetWeaponLabelColor.cs b/Scripts/MinEventActions/MinEventActionSetWeaponLabelColor.cs new file mode 100644 index 0000000..371faee --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionSetWeaponLabelColor.cs @@ -0,0 +1,51 @@ +using System.Xml.Linq; +using UnityEngine; + +public class MinEventActionSetWeaponLabelColor : MinEventActionRemoteHoldingBase +{ + private bool isText = true; + private int slot0 = 0; + private int slot1 = 0; + private Color color; + private int nameId; + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + bool flag = base.ParseXmlAttribute(_attribute); + if (!flag) + { + string value = _attribute.Value; + flag = true; + switch (_attribute.Name.LocalName) + { + case "is_text": + isText = bool.Parse(value); + break; + case "slot0": + slot0 = int.Parse(value); + break; + case "slot1": + slot1 = int.Parse(value); + break; + case "color": + flag = ColorUtility.TryParseHtmlString(value, out color); + break; + case "name": + nameId = Shader.PropertyToID(value); + break; + default: + flag = false; + break; + } + } + return flag; + } + public override void Execute(MinEventParams _params) + { + if (isRemoteHolding || localOnly) + NetPackageSyncWeaponLabelColor.SetWeaponLabelColor(_params.Self, isText, slot0, color, slot1, nameId); + else if (!_params.Self.isEntityRemote) + NetPackageSyncWeaponLabelColor.NetSyncSetWeaponLabelColor(_params.Self, isText, slot0, color, slot1, nameId); + } +} + diff --git a/Scripts/MinEventActions/MinEventActionUpdateLocalCache.cs b/Scripts/MinEventActions/MinEventActionUpdateLocalCache.cs new file mode 100644 index 0000000..b67e5fe --- /dev/null +++ b/Scripts/MinEventActions/MinEventActionUpdateLocalCache.cs @@ -0,0 +1,49 @@ +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System; +using System.Xml.Linq; + +public class MinEventActionUpdateLocalCache : MinEventActionBase +{ + private PassiveEffects passive; + private FastTags tags; + private int actionIndex = -1; + private int saveAs; + private string saveAsStr; + public override bool CanExecute(MinEventTypes _eventType, MinEventParams _params) + { + return !_params.Self.isEntityRemote && (actionIndex < 0 ? _params.ItemActionData : _params.ItemActionData.invData.actionData[actionIndex]) is IModuleContainerFor && base.CanExecute(_eventType, _params); + } + + public override void Execute(MinEventParams _params) + { + ActionModuleLocalPassiveCache.LocalPassiveCacheData _data = ((IModuleContainerFor)(actionIndex < 0 ? _params.ItemActionData : _params.ItemActionData.invData.actionData[actionIndex])).Instance; + + _data.CachePassive(passive, saveAs, saveAsStr, tags); + } + + public override bool ParseXmlAttribute(XAttribute _attribute) + { + if (base.ParseXmlAttribute(_attribute)) + return true; + + switch (_attribute.Name.LocalName) + { + case "passive": + passive = CustomEffectEnumManager.RegisterOrGetEnum(_attribute.Value, true); + return true; + case "tags": + tags = FastTags.Parse(_attribute.Value); + return true; + case "action_index": + actionIndex = int.Parse(_attribute.Value); + return true; + case "as": + saveAsStr = _attribute.Value; + saveAs = _attribute.Value.GetHashCode(); + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Scripts/NetPackages/NetPackageEntityActionIndex.cs b/Scripts/NetPackages/NetPackageEntityActionIndex.cs new file mode 100644 index 0000000..a087684 --- /dev/null +++ b/Scripts/NetPackages/NetPackageEntityActionIndex.cs @@ -0,0 +1,42 @@ +using KFCommonUtilityLib.Scripts.StaticManagers; + +namespace KFCommonUtilityLib.Scripts.NetPackages +{ + public class NetPackageEntityActionIndex : NetPackage + { + private int entityID; + private int mode; + public NetPackageEntityActionIndex Setup(int entityID, int mode) + { + this.entityID = entityID; + this.mode = mode; + return this; + } + + public override int GetLength() + { + return 5; + } + + public override void ProcessPackage(World _world, GameManager _callbacks) + { + if (MultiActionManager.SetModeForEntity(entityID, mode) && ConnectionManager.Instance.IsServer) + { + ConnectionManager.Instance.SendPackage(NetPackageManager.GetPackage().Setup(entityID, mode), false, -1, entityID); + } + } + + public override void write(PooledBinaryWriter _writer) + { + base.write(_writer); + _writer.Write(entityID); + _writer.Write((byte)mode); + } + + public override void read(PooledBinaryReader _reader) + { + entityID = _reader.ReadInt32(); + mode = _reader.ReadByte(); + } + } +} diff --git a/Scripts/NetPackages/NetPackageEntitySpawnWithCVar.cs b/Scripts/NetPackages/NetPackageEntitySpawnWithCVar.cs new file mode 100644 index 0000000..33f6eb8 --- /dev/null +++ b/Scripts/NetPackages/NetPackageEntitySpawnWithCVar.cs @@ -0,0 +1,81 @@ +namespace KFCommonUtilityLib.Scripts.NetPackages +{ + public class NetPackageEntitySpawnWithCVar : NetPackageEntitySpawn + { + byte[] cvarData; + public NetPackageEntitySpawnWithCVar Setup(EntityCreationData _es, EntityAlive _ea) + { + Setup(_es); + using (var bw = MemoryPools.poolBinaryWriter.AllocSync(true)) + { + using (var ms = MemoryPools.poolMemoryStream.AllocSync(true)) + { + bw.SetBaseStream(ms); + if (_ea && _ea.Buffs != null) + { + var buff = _ea.Buffs; + bw.Write(buff.CVars.Count); + foreach (var cvar in buff.CVars) + { + bw.Write(cvar.Key); + bw.Write(cvar.Value); + } + } + else + { + bw.Write(0); + } + cvarData = ms.ToArray(); + } + } + return this; + } + + public override int GetLength() + { + return base.GetLength() + 200; + } + + public override void ProcessPackage(World _world, GameManager _callbacks) + { + base.ProcessPackage(_world, _callbacks); + if (_world == null || _callbacks == null || es.id == -1) + { + return; + } + EntityAlive ea = _world.GetEntity(es.id) as EntityAlive; + if (!ea) + { + return; + } + using (var ms = MemoryPools.poolMemoryStream.AllocSync(true)) + { + ms.Write(cvarData, 0, cvarData.Length); + ms.Position = 0; + using (var br = MemoryPools.poolBinaryReader.AllocSync(true)) + { + br.SetBaseStream(ms); + var count = br.ReadInt32(); + for (int i = 0; i < count; i++) + { + ea.Buffs.SetCustomVar(br.ReadString(), br.ReadSingle(), false); + } + } + } + ea.FireEvent(CustomEnums.onSelfFirstCVarSync); + } + + public override void read(PooledBinaryReader _reader) + { + base.read(_reader); + cvarData = _reader.ReadBytes(_reader.ReadInt32()); + } + + public override void write(PooledBinaryWriter _writer) + { + base.write(_writer); + _writer.Write(cvarData.Length); + _writer.Write(cvarData); + } + } +} diff --git a/Scripts/NetPackages/NetPackageFixedReload.cs b/Scripts/NetPackages/NetPackageFixedReload.cs new file mode 100644 index 0000000..daaf677 --- /dev/null +++ b/Scripts/NetPackages/NetPackageFixedReload.cs @@ -0,0 +1,49 @@ +using KFCommonUtilityLib.Scripts.Utilities; + +class NetPackageFixedReload : NetPackage +{ + private int entityId; + private byte actionIndex; + + public NetPackageFixedReload Setup(int entityId, int actionIndex) + { + this.entityId = entityId; + this.actionIndex = (byte)actionIndex; + return this; + } + + public override int GetLength() + { + return 5; + } + + public override void ProcessPackage(World _world, GameManager _callbacks) + { + if (_world == null) + { + return; + } + + if (!_world.IsRemote()) + { + MultiActionUtils.FixedItemReloadServer(entityId, actionIndex); + } + else + { + MultiActionUtils.FixedItemReloadClient(entityId, actionIndex); + } + } + + public override void read(PooledBinaryReader _reader) + { + entityId = _reader.ReadInt32(); + actionIndex = _reader.ReadByte(); + } + + public override void write(PooledBinaryWriter _writer) + { + base.write(_writer); + _writer.Write(entityId); + _writer.Write(actionIndex); + } +} \ No newline at end of file diff --git a/Scripts/NetPackages/NetPackageRemoteAttachPrefab.cs b/Scripts/NetPackages/NetPackageRemoteAttachPrefab.cs new file mode 100644 index 0000000..b94efb8 --- /dev/null +++ b/Scripts/NetPackages/NetPackageRemoteAttachPrefab.cs @@ -0,0 +1,69 @@ +using UnityEngine; + +namespace KFCommonUtilityLib.Scripts.NetPackages +{ + public class NetPackageRemoteAttachPrefab : NetPackage + { + private int entityID; + private string prefab; + private string path; + private Vector3 localPosition; + private Vector3 localRotation; + private Vector3 localScale; + + public NetPackageRemoteAttachPrefab Setup(int entityID, string prefab, string path, Vector3 localPosition, Vector3 localRotation, Vector3 localScale) + { + this.entityID = entityID; + this.prefab = prefab; + this.path = path; + this.localPosition = localPosition; + this.localRotation = localRotation; + this.localScale = localScale; + return this; + } + + public override int GetLength() + { + return 200; + } + + public override void ProcessPackage(World _world, GameManager _callbacks) + { + if (_world == null || _callbacks == null) + { + return; + } + var entity = _world.GetEntity(entityID) as EntityAlive; + if (!entity || !entity.isEntityRemote) + { + return; + } + if (ConnectionManager.Instance.IsServer) + { + ConnectionManager.Instance.SendPackage(NetPackageManager.GetPackage().Setup(entityID, prefab, path, localPosition, localRotation, localScale), false, -1, -1, entityID); + } + MinEventActionAttachPrefabToEntitySync.RemoteAttachPrefab(entity, prefab, path, localPosition, localRotation, localScale); + } + + public override void read(PooledBinaryReader _reader) + { + entityID = _reader.ReadInt32(); + prefab = _reader.ReadString(); + path = _reader.ReadString(); + localPosition = StreamUtils.ReadVector3(_reader); + localRotation = StreamUtils.ReadVector3(_reader); + localScale = StreamUtils.ReadVector3(_reader); + } + + public override void write(PooledBinaryWriter _writer) + { + base.write(_writer); + _writer.Write(entityID); + _writer.Write(prefab); + _writer.Write(path); + StreamUtils.Write(_writer, localPosition); + StreamUtils.Write(_writer, localRotation); + StreamUtils.Write(_writer, localScale); + } + } +} diff --git a/Scripts/NetPackages/NetPackageSyncWeaponLabelColor.cs b/Scripts/NetPackages/NetPackageSyncWeaponLabelColor.cs new file mode 100644 index 0000000..e4652a1 --- /dev/null +++ b/Scripts/NetPackages/NetPackageSyncWeaponLabelColor.cs @@ -0,0 +1,117 @@ +using UnityEngine; + +class NetPackageSyncWeaponLabelColor : NetPackage +{ + public NetPackageSyncWeaponLabelColor Setup(int entityId, bool isText, Color color, int index0, int index1, int nameId) + { + this.entityId = entityId; + this.isText = isText; + this.color = color; + this.index0 = index0; + if (!isText) + { + this.index1 = index1; + this.nameId = nameId; + } + return this; + } + + public override int GetLength() + { + return isText ? 20 : 28; + } + + public override void ProcessPackage(World _world, GameManager _callbacks) + { + if (_world == null) + return; + + NetSyncSetWeaponLabelColor(_world.GetEntity(entityId) as EntityAlive, isText, index0, color, index1, nameId, true); + } + + public static void NetSyncSetWeaponLabelColor(EntityAlive holdingEntity, bool isText, int slot0, Color color, int slot1, int nameId, bool fromNet = false) + { + if (!holdingEntity || (holdingEntity.isEntityRemote && !fromNet)) + { + if (holdingEntity) + Log.Out("netsync failed! isEntityRemote: " + holdingEntity.isEntityRemote + " fromNet: " + fromNet); + else + Log.Out("Entity not found!"); + return; + } + + if (SetWeaponLabelColor(holdingEntity, isText, slot0, color, slot1, nameId)) + { + //Log.Out("trying to set weapon label on " + (SingletonMonoBehaviour.Instance.IsServer ? "server" : "client") + " color: " + color.ToString() + " entity: " + holdingEntity.entityId + " from net: " + fromNet); + if (SingletonMonoBehaviour.Instance.IsServer && SingletonMonoBehaviour.Instance.ClientCount() > 0) + { + int allButAttachedToEntityId = holdingEntity.entityId; + if (holdingEntity && holdingEntity.AttachedMainEntity) + allButAttachedToEntityId = holdingEntity.AttachedMainEntity.entityId; + SingletonMonoBehaviour.Instance.SendPackage(NetPackageManager.GetPackage().Setup(holdingEntity.entityId, isText, color, slot0, slot1, nameId), false, -1, allButAttachedToEntityId, allButAttachedToEntityId, null, 15); + } + else if (SingletonMonoBehaviour.Instance.IsClient && !fromNet) + SingletonMonoBehaviour.Instance.SendToServer(NetPackageManager.GetPackage().Setup(holdingEntity.entityId, isText, color, slot0, slot1, nameId)); + } + } + + public static bool SetWeaponLabelColor(EntityAlive holdingEntity, bool isText, int slot0, Color color, int slot1, int nameId) + { + if (GameManager.IsDedicatedServer) + return true; + + if (isText) + { + WeaponLabelControllerBase controller = holdingEntity.inventory.GetHoldingItemTransform()?.GetComponent(); + //if (holdingEntity.emodel.avatarController is AvatarMultiBodyController multiBody && multiBody.HeldItemTransform != null) + // controller = multiBody.HeldItemTransform.GetComponent(); + //else if (holdingEntity.emodel.avatarController is LegacyAvatarController legacy && legacy.HeldItemTransform != null) + // controller = legacy.HeldItemTransform.GetComponent(); + return controller && controller.setLabelColor(slot0, color); + } + else + { + WeaponColorControllerBase controller = holdingEntity.inventory.GetHoldingItemTransform()?.GetComponent(); + //if (holdingEntity.emodel.avatarController is AvatarMultiBodyController multiBody && multiBody.HeldItemTransform != null) + // controller = multiBody.HeldItemTransform.GetComponent(); + //else if (holdingEntity.emodel.avatarController is LegacyAvatarController legacy && legacy.HeldItemTransform != null) + // controller = legacy.HeldItemTransform.GetComponent(); + return controller && controller.setMaterialColor(slot0, slot1, nameId, color); + } + } + + public override void read(PooledBinaryReader _reader) + { + entityId = _reader.ReadInt32(); + isText = _reader.ReadBoolean(); + color = StreamUtils.ReadColor(_reader); + index0 = _reader.ReadChar(); + if (!isText) + { + index1 = _reader.ReadChar(); + nameId = _reader.ReadInt32(); + } + } + + public override void write(PooledBinaryWriter _writer) + { + base.write(_writer); + _writer.Write(entityId); + _writer.Write(isText); + StreamUtils.Write(_writer, color); + _writer.Write((char)index0); + if (!isText) + { + _writer.Write((char)index1); + _writer.Write(nameId); + } + } + + private int entityId; + private bool isText; + private Color color; + private int index0; + private int index1; + private int nameId; +} + diff --git a/Scripts/NetPackages/NetPackageSyncWeaponLabelText.cs b/Scripts/NetPackages/NetPackageSyncWeaponLabelText.cs new file mode 100644 index 0000000..a505b24 --- /dev/null +++ b/Scripts/NetPackages/NetPackageSyncWeaponLabelText.cs @@ -0,0 +1,82 @@ +class NetPackageSyncWeaponLabelText : NetPackage +{ + public NetPackageSyncWeaponLabelText Setup(int entityId, int slot, string data) + { + this.entityId = entityId; + this.slot = slot; + this.data = data; + return this; + } + public override int GetLength() + { + return 6 + data.Length; + } + + public override void ProcessPackage(World _world, GameManager _callbacks) + { + if (_world == null) + return; + + NetSyncSetWeaponLabelText(_world.GetEntity(entityId) as EntityAlive, slot, data, true); + } + + public override void read(PooledBinaryReader _reader) + { + entityId = _reader.ReadInt32(); + slot = (int)_reader.ReadChar(); + data = _reader.ReadString(); + } + + public override void write(PooledBinaryWriter _writer) + { + base.write(_writer); + _writer.Write(entityId); + _writer.Write((char)slot); + _writer.Write(data); + } + + public static void NetSyncSetWeaponLabelText(EntityAlive holdingEntity, int slot, string data, bool fromNet = false) + { + if (!holdingEntity || (holdingEntity.isEntityRemote && !fromNet)) + { + if (holdingEntity) + Log.Out("netsync failed! isEntityRemote: " + holdingEntity.isEntityRemote + " fromNet: " + fromNet); + else + Log.Out("Entity not found!"); + return; + } + + if (SetWeaponLabelText(holdingEntity, slot, data)) + { + //Log.Out("trying to set weapon label on " + (SingletonMonoBehaviour.Instance.IsServer ? "server" : "client") + " slot: " + slot + " text: " + data + " entity: " + holdingEntity.entityId + " from net: " + fromNet); + if (SingletonMonoBehaviour.Instance.IsServer && SingletonMonoBehaviour.Instance.ClientCount() > 0) + { + int allButAttachedToEntityId = holdingEntity.entityId; + if (holdingEntity.AttachedMainEntity) + allButAttachedToEntityId = holdingEntity.AttachedMainEntity.entityId; + SingletonMonoBehaviour.Instance.SendPackage(NetPackageManager.GetPackage().Setup(holdingEntity.entityId, slot, data), false, -1, allButAttachedToEntityId, allButAttachedToEntityId, null, 15); + } + else if (SingletonMonoBehaviour.Instance.IsClient && !fromNet) + SingletonMonoBehaviour.Instance.SendToServer(NetPackageManager.GetPackage().Setup(holdingEntity.entityId, slot, data)); + } + } + + public static bool SetWeaponLabelText(EntityAlive holdingEntity, int slot, string data) + { + if (GameManager.IsDedicatedServer) + return true; + + WeaponLabelControllerBase controller = holdingEntity.inventory.GetHoldingItemTransform()?.GetComponent(); + //if (holdingEntity.emodel.avatarController is AvatarMultiBodyController multiBody && multiBody.HeldItemTransform != null) + // controller = multiBody.HeldItemTransform.GetComponent(); + //else if (holdingEntity.emodel.avatarController is LegacyAvatarController legacy && legacy.HeldItemTransform) + // controller = legacy.HeldItemTransform.GetComponent(); + + return controller && controller.setLabelText(slot, data); + } + + private int entityId; + private int slot; + private string data; +} + diff --git a/Scripts/Requirements/ActionHasTags.cs b/Scripts/Requirements/ActionHasTags.cs new file mode 100644 index 0000000..cbaa4c3 --- /dev/null +++ b/Scripts/Requirements/ActionHasTags.cs @@ -0,0 +1,52 @@ +using KFCommonUtilityLib; +using System.Xml.Linq; + +public class ActionHasTags : TargetedCompareRequirementBase +{ + private FastTags actionTags; + + private bool hasAllTags; + + public override bool IsValid(MinEventParams _params) + { + if (!base.IsValid(_params)) + { + return false; + } + + bool flag = false; + if (_params.ItemActionData is IModuleContainerFor tagged) + { + flag = (hasAllTags ? tagged.Instance.tags.Test_AllSet(actionTags) : tagged.Instance.tags.Test_AnySet(actionTags)); + } + + if (!invert) + { + return flag; + } + + return !flag; + } + + public override bool ParseXAttribute(XAttribute _attribute) + { + bool flag = base.ParseXAttribute(_attribute); + if (!flag) + { + string localName = _attribute.Name.LocalName; + if (localName == "tags") + { + actionTags = FastTags.Parse(_attribute.Value); + return true; + } + + if (localName == "has_all_tags") + { + hasAllTags = StringParsers.ParseBool(_attribute.Value); + return true; + } + } + + return flag; + } +} \ No newline at end of file diff --git a/Scripts/Requirements/ActionIndexIs.cs b/Scripts/Requirements/ActionIndexIs.cs new file mode 100644 index 0000000..cd866e4 --- /dev/null +++ b/Scripts/Requirements/ActionIndexIs.cs @@ -0,0 +1,31 @@ +using System; +using System.Xml.Linq; + +public class ActionIndexIs : RequirementBase +{ + protected int index; + public override bool IsValid(MinEventParams _params) + { + //if (!res) + //{ + // Log.Out($"Action index is not {index} : {(_params.ItemActionData == null ? "null" : _params.ItemActionData.indexInEntityOfAction.ToString())}\n{StackTraceUtility.ExtractStackTrace()}"); + //} + var res = (_params.ItemActionData == null && index == 0) || _params.ItemActionData?.indexInEntityOfAction == index; + return invert ? !res : res; + } + + public override bool ParamsValid(MinEventParams _params) + { + return true; + } + + public override bool ParseXAttribute(XAttribute _attribute) + { + if (_attribute.Name == "index") + { + index = Math.Max(int.Parse(_attribute.Value), 0); + return true; + } + return false; + } +} diff --git a/Scripts/Requirements/AmmoIndexIs.cs b/Scripts/Requirements/AmmoIndexIs.cs new file mode 100644 index 0000000..60608d5 --- /dev/null +++ b/Scripts/Requirements/AmmoIndexIs.cs @@ -0,0 +1,44 @@ +using KFCommonUtilityLib.Scripts.Utilities; +using System.Xml.Linq; + +public class AmmoIndexIs : RequirementBase +{ + protected int ammoIndex; + protected int actionIndex; + protected ItemValue itemValueCache; + + public override bool IsValid(MinEventParams _params) + { + bool res = false; + int parAmmoIndex = itemValueCache.GetSelectedAmmoIndexByActionIndex(actionIndex); + res = parAmmoIndex == ammoIndex; + itemValueCache = null; + if (invert) + { + return !res; + } + return res; + } + + public override bool ParamsValid(MinEventParams _params) + { + itemValueCache = _params.ItemValue; + return itemValueCache != null; + } + + public override bool ParseXAttribute(XAttribute _attribute) + { + switch(_attribute.Name.LocalName) + { + case "ammoIndex": + ammoIndex = int.Parse(_attribute.Value); + break; + case "actionIndex": + actionIndex = int.Parse(_attribute.Value); + break; + default: + return false; + } + return true; + } +} \ No newline at end of file diff --git a/Scripts/Requirements/FireModeIs.cs b/Scripts/Requirements/FireModeIs.cs new file mode 100644 index 0000000..9701e8b --- /dev/null +++ b/Scripts/Requirements/FireModeIs.cs @@ -0,0 +1,32 @@ +using KFCommonUtilityLib; +using System; +using System.Xml.Linq; + +public class FireModeIs : RequirementBase +{ + protected int index; + public override bool IsValid(MinEventParams _params) + { + bool res = false; + if (_params.ItemActionData is IModuleContainerFor dataModule) + { + res = dataModule.Instance.currentFireMode == index; + } + return invert ? !res : res; + } + + public override bool ParamsValid(MinEventParams _params) + { + return true; + } + + public override bool ParseXAttribute(XAttribute _attribute) + { + if (_attribute.Name == "index") + { + index = Math.Max(int.Parse(_attribute.Value), 0); + return true; + } + return false; + } +} \ No newline at end of file diff --git a/Scripts/Requirements/HoldingActionIndexIs.cs b/Scripts/Requirements/HoldingActionIndexIs.cs new file mode 100644 index 0000000..756e5bf --- /dev/null +++ b/Scripts/Requirements/HoldingActionIndexIs.cs @@ -0,0 +1,9 @@ +using KFCommonUtilityLib.Scripts.StaticManagers; + +public class HoldingActionIndexIs : ActionIndexIs +{ + public override bool IsValid(MinEventParams _params) + { + return (MultiActionManager.GetActionIndexForEntity(_params.Self) == index) ^ invert; + } +} diff --git a/Scripts/Requirements/HoldingAmmoIndexIs.cs b/Scripts/Requirements/HoldingAmmoIndexIs.cs new file mode 100644 index 0000000..7c74a97 --- /dev/null +++ b/Scripts/Requirements/HoldingAmmoIndexIs.cs @@ -0,0 +1,8 @@ +public class HoldingAmmoIndexIs : AmmoIndexIs +{ + public override bool ParamsValid(MinEventParams _params) + { + itemValueCache = _params.Self?.inventory?.holdingItemItemValue; + return itemValueCache != null; + } +} \ No newline at end of file diff --git a/Scripts/Requirements/HoldingFireModeIs.cs b/Scripts/Requirements/HoldingFireModeIs.cs new file mode 100644 index 0000000..4ca3864 --- /dev/null +++ b/Scripts/Requirements/HoldingFireModeIs.cs @@ -0,0 +1,33 @@ +using KFCommonUtilityLib; +using KFCommonUtilityLib.Scripts.StaticManagers; +using System; +using System.Xml.Linq; + +public class HoldingFireModeIs : RequirementBase +{ + protected int index; + public override bool IsValid(MinEventParams _params) + { + bool res = false; + if (_params.Self && _params.Self?.inventory?.holdingItemData?.actionData[MultiActionManager.GetActionIndexForEntity(_params.Self)] is IModuleContainerFor dataModule) + { + res = dataModule.Instance.currentFireMode == index; + } + return invert ? !res : res; + } + + public override bool ParamsValid(MinEventParams _params) + { + return true; + } + + public override bool ParseXAttribute(XAttribute _attribute) + { + if (_attribute.Name == "index") + { + index = Math.Max(int.Parse(_attribute.Value), 0); + return true; + } + return false; + } +} \ No newline at end of file diff --git a/Scripts/Requirements/IsActionUnlocked.cs b/Scripts/Requirements/IsActionUnlocked.cs new file mode 100644 index 0000000..7868e84 --- /dev/null +++ b/Scripts/Requirements/IsActionUnlocked.cs @@ -0,0 +1,28 @@ +using KFCommonUtilityLib; +using System.Xml.Linq; + +public class IsActionUnlocked : TargetedCompareRequirementBase +{ + protected int actionIndex; + + public override bool IsValid(MinEventParams _params) + { + return base.IsValid(_params) && + ((actionIndex == 0 || + (_params.ItemActionData?.invData?.actionData?[0] is IModuleContainerFor alt + && alt.Instance.IsActionUnlocked(actionIndex))) ^ invert); + } + + public override bool ParseXAttribute(XAttribute _attribute) + { + if (base.ParseXAttribute(_attribute)) + return true; + + if (_attribute.Name == "index") + { + actionIndex = int.Parse(_attribute.Value); + return true; + } + return false; + } +} diff --git a/Scripts/Requirements/IsHoldingItemModificationActivated.cs b/Scripts/Requirements/IsHoldingItemModificationActivated.cs new file mode 100644 index 0000000..1b92ee5 --- /dev/null +++ b/Scripts/Requirements/IsHoldingItemModificationActivated.cs @@ -0,0 +1,64 @@ +using UniLinq; +using System.Xml.Linq; +using UnityEngine; + +public class IsHoldingItemModificationActivated : RequirementBase +{ + private string modName; + private int modId = -1; + + public override bool IsValid(MinEventParams _params) + { + if (modId < 0) + { + modId = ItemClass.GetItemClass(modName)?.Id ?? -1; + //Log.Out($"modId {modId}"); + if (modId < 0) + return false; + } + + ItemValue itemValue = _params.Self?.inventory?.holdingItemItemValue; + //Log.Out($"modName {modName} modId {modId} item {_params?.ItemValue?.ItemClass?.Name ?? "null"} mods{(_params?.ItemValue?.Modifications == null ? ": null" : itemValue.Modifications.Select(v => $"\n{(v == null || v.IsEmpty() ? "null" : $"item {v.ItemClass.Name} type {v.type} activated {v.Activated}")}").Join())} \ncos{(_params?.ItemValue?.CosmeticMods == null ? ": null" : itemValue.CosmeticMods.Select(v => $"\n{(v == null || v.IsEmpty() ? "null" : $"item {v.ItemClass.Name} type {v.type} activated {v.Activated}")}").Join())} \n{StackTraceUtility.ExtractStackTrace()}"); + if (itemValue != null) + { + if (itemValue.Modifications != null) + { + foreach (var mod in itemValue.Modifications) + { + if (mod != null && mod.type == modId && mod.Activated > 0) + { + return !invert; + } + } + } + + if (itemValue.CosmeticMods != null) + { + foreach (var cos in itemValue.CosmeticMods) + { + if (cos != null && cos.type == modId && cos.Activated > 0) + { + return !invert; + } + } + } + } + + return invert; + } + + public override bool ParseXAttribute(XAttribute _attribute) + { + if (base.ParseXAttribute(_attribute)) + return true; + + switch (_attribute.Name.LocalName) + { + case "mod": + modName = _attribute.Value; + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Scripts/Requirements/IsInJeep.cs b/Scripts/Requirements/IsInJeep.cs new file mode 100644 index 0000000..e941c13 --- /dev/null +++ b/Scripts/Requirements/IsInJeep.cs @@ -0,0 +1,15 @@ +public class IsInJeep : IsAttachedToEntity +{ + public override bool IsValid(MinEventParams _params) + { + if (!base.IsValid(_params)) + { + return false; + } + if (invert) + { + return !(target.AttachedToEntity is EntityVJeep); + } + return target.AttachedToEntity is EntityVJeep; + } +} diff --git a/Scripts/Requirements/IsLocal.cs b/Scripts/Requirements/IsLocal.cs new file mode 100644 index 0000000..21c1db1 --- /dev/null +++ b/Scripts/Requirements/IsLocal.cs @@ -0,0 +1,7 @@ +public class IsLocal : RequirementBase +{ + public override bool IsValid(MinEventParams _params) + { + return base.IsValid(_params) && ((_params.IsLocal || (_params.Self && !_params.Self.isEntityRemote)) ^ invert); + } +} \ No newline at end of file diff --git a/Scripts/Requirements/IsModificationActivated.cs b/Scripts/Requirements/IsModificationActivated.cs new file mode 100644 index 0000000..2a7bb2d --- /dev/null +++ b/Scripts/Requirements/IsModificationActivated.cs @@ -0,0 +1,63 @@ +using UniLinq; +using System.Xml.Linq; +using UnityEngine; + +public class IsModificationActivated : RequirementBase +{ + private string modName; + private int modId = -1; + + public override bool IsValid(MinEventParams _params) + { + if (modId < 0) + { + modId = ItemClass.GetItemClass(modName)?.Id ?? -1; + //Log.Out($"modId {modId}"); + if (modId < 0) + return false; + } + + //Log.Out($"modName {modName} modId {modId} item {_params?.ItemValue?.ItemClass?.Name ?? "null"} mods{(_params?.ItemValue?.Modifications == null ? ": null" : _params.ItemValue.Modifications.Select(v => $"\n{(v == null || v.IsEmpty() ? "null" : $"item {v.ItemClass.Name} type {v.type} activated {v.Activated}")}").Join())} \ncos{(_params?.ItemValue?.CosmeticMods == null ? ": null" : _params.ItemValue.CosmeticMods.Select(v => $"\n{(v == null || v.IsEmpty() ? "null" : $"item {v.ItemClass.Name} type {v.type} activated {v.Activated}")}").Join())} \n{StackTraceUtility.ExtractStackTrace()}"); + if (_params.ItemValue != null) + { + if (_params.ItemValue.Modifications != null) + { + foreach (var mod in _params.ItemValue.Modifications) + { + if (mod != null && mod.type == modId && mod.Activated > 0) + { + return !invert; + } + } + } + + if (_params.ItemValue.CosmeticMods != null) + { + foreach (var cos in _params.ItemValue.CosmeticMods) + { + if (cos != null && cos.type == modId && cos.Activated > 0) + { + return !invert; + } + } + } + } + + return invert; + } + + public override bool ParseXAttribute(XAttribute _attribute) + { + if (base.ParseXAttribute(_attribute)) + return true; + + switch (_attribute.Name.LocalName) + { + case "mod": + modName = _attribute.Value; + return true; + } + + return false; + } +} \ No newline at end of file diff --git a/Scripts/Requirements/ItemActionIndexIs.cs b/Scripts/Requirements/ItemActionIndexIs.cs new file mode 100644 index 0000000..dd71424 --- /dev/null +++ b/Scripts/Requirements/ItemActionIndexIs.cs @@ -0,0 +1,7 @@ +//public class ItemActionIndexIs : ActionIndexIs +//{ +// public override bool IsValid(MinEventParams _params) +// { +// return (_params.ItemValue == null && index == 0) || _params.ItemValue?.GetActionIndexForItemValue() == index; +// } +//} \ No newline at end of file diff --git a/Scripts/Requirements/ItemInInventory.cs b/Scripts/Requirements/ItemInInventory.cs new file mode 100644 index 0000000..497be89 --- /dev/null +++ b/Scripts/Requirements/ItemInInventory.cs @@ -0,0 +1,33 @@ +using System.Xml.Linq; + +public class ItemInInventory : RequirementBase +{ + private string itemName; + private ItemValue itemValueCache = null; + + public override bool IsValid(MinEventParams _params) + { + return base.IsValid(_params) && compareValues(_params.Self.GetItemCount(itemValueCache), operation, value) ^ invert; + } + + public override bool ParamsValid(MinEventParams _params) + { + if (itemValueCache == null) + itemValueCache = ItemClass.GetItem(itemName); + return base.ParamsValid(_params) && itemValueCache != null; + } + + public override bool ParseXAttribute(XAttribute _attribute) + { + if (base.ParseXAttribute(_attribute)) + return true; + + string name = _attribute.Name.LocalName; + if (name == "item") + { + itemName = _attribute.Value; + return true; + } + return false; + } +} diff --git a/Scripts/Requirements/PercentInHoldingItem.cs b/Scripts/Requirements/PercentInHoldingItem.cs new file mode 100644 index 0000000..9ca87fa --- /dev/null +++ b/Scripts/Requirements/PercentInHoldingItem.cs @@ -0,0 +1,17 @@ +using KFCommonUtilityLib.Scripts.StaticManagers; + +public class PercentInHoldingItem : RoundsInHoldingItem +{ + public override bool IsValid(MinEventParams _params) + { + if (!ParamsValid(_params)) + return false; + + ItemValue holdingItemValue = _params.Self.inventory.holdingItemItemValue; + int actionIndex = MultiActionManager.GetActionIndexForEntity(_params.Self); + if (holdingItemValue.IsEmpty() || !(holdingItemValue.ItemClass.Actions[actionIndex] is ItemActionRanged _ranged)) + return false; + return RequirementBase.compareValues((float)(roundsBeforeShot ? holdingItemValue.Meta + 1 : holdingItemValue.Meta) / _ranged.GetMaxAmmoCount(_params.Self.inventory.holdingItemData.actionData[actionIndex]), operation, value) ^ invert; + } +} + diff --git a/Scripts/Requirements/PercentInMagazine.cs b/Scripts/Requirements/PercentInMagazine.cs new file mode 100644 index 0000000..0ec6628 --- /dev/null +++ b/Scripts/Requirements/PercentInMagazine.cs @@ -0,0 +1,14 @@ +public class PercentInMagazine : RoundsInMagazineBase +{ + public override bool IsValid(MinEventParams _params) + { + if (!ParamsValid(_params)) + return false; + + if (_params.ItemValue.IsEmpty() || !(_params.ItemActionData is ItemActionRanged.ItemActionDataRanged _rangedData) || _params.ItemActionData.invData == null) + return false; + + return RequirementBase.compareValues((float)(roundsBeforeShot ? _params.ItemValue.Meta + 1 : _params.ItemValue.Meta) / ((ItemActionRanged)_params.ItemValue.ItemClass.Actions[_rangedData.indexInEntityOfAction]).GetMaxAmmoCount(_params.ItemActionData), operation, value) ^ invert; + } +} + diff --git a/Scripts/Requirements/RoundsInHoldingItem.cs b/Scripts/Requirements/RoundsInHoldingItem.cs new file mode 100644 index 0000000..f1da9eb --- /dev/null +++ b/Scripts/Requirements/RoundsInHoldingItem.cs @@ -0,0 +1,17 @@ +using KFCommonUtilityLib.Scripts.StaticManagers; + +public class RoundsInHoldingItem : RoundsInMagazineBase +{ + public override bool IsValid(MinEventParams _params) + { + if (!ParamsValid(_params)) + return false; + + ItemValue holdingItemValue = _params.Self.inventory.holdingItemItemValue; + if (holdingItemValue.IsEmpty() || !(holdingItemValue.ItemClass.Actions[MultiActionManager.GetActionIndexForEntity(_params.Self)] is ItemActionRanged)) + return false; + + return RequirementBase.compareValues((float)(roundsBeforeShot ? holdingItemValue.Meta + 1 : holdingItemValue.Meta), operation, value) ^ invert; + } +} + diff --git a/Scripts/Requirements/RoundsInInventory.cs b/Scripts/Requirements/RoundsInInventory.cs new file mode 100644 index 0000000..d2b2465 --- /dev/null +++ b/Scripts/Requirements/RoundsInInventory.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; + +public class RoundsInInventory : RequirementBase +{ + private static Dictionary cached = new Dictionary(); + + public static bool TryGetValue(string ammoName, out ItemValue ammoValue) + { + if (!cached.TryGetValue(ammoName, out ammoValue)) + { + ammoValue = ItemClass.GetItem(ammoName, false); + if (ammoValue == null) + return false; + cached.Add(ammoName, ammoValue); + } + return true; + } + public override bool IsValid(MinEventParams _params) + { + if (!this.ParamsValid(_params)) + return invert; + + ItemValue itemValue = _params.ItemValue; + if (itemValue.IsEmpty() || !(_params.ItemActionData is ItemActionRanged.ItemActionDataRanged _rangedData)) + return invert; + + string ammoName = ((ItemActionRanged)itemValue.ItemClass.Actions[_rangedData.indexInEntityOfAction]).MagazineItemNames[itemValue.SelectedAmmoTypeIndex]; + if (TryGetValue(ammoName, out var ammoValue)) + return compareValues(_params.Self.GetItemCount(ammoValue), this.operation, this.value) ^ invert; + return invert; + } +} diff --git a/Scripts/Requirements/RoundsInMagazineBase.cs b/Scripts/Requirements/RoundsInMagazineBase.cs new file mode 100644 index 0000000..e4891f4 --- /dev/null +++ b/Scripts/Requirements/RoundsInMagazineBase.cs @@ -0,0 +1,21 @@ +using System.Xml.Linq; + +public class RoundsInMagazineBase : RoundsInMagazine +{ + protected bool roundsBeforeShot = false; + + public override bool ParseXAttribute(XAttribute _attribute) + { + if (base.ParseXAttribute(_attribute)) + return true; + + if (_attribute.Name.LocalName == "rounds_before_shot") + { + roundsBeforeShot = bool.Parse(_attribute.Value); + return true; + } + + return false; + } +} + diff --git a/Scripts/StaticManagers/AnimationRiggingManager.cs b/Scripts/StaticManagers/AnimationRiggingManager.cs new file mode 100644 index 0000000..3e247de --- /dev/null +++ b/Scripts/StaticManagers/AnimationRiggingManager.cs @@ -0,0 +1,437 @@ +using System.Collections.Generic; +using UniLinq; +using UnityEngine; + +namespace KFCommonUtilityLib.Scripts.StaticManagers +{ + public static class AnimationRiggingManager + { + //public class FpvTransformRef + //{ + // public Animator fpvAnimator; + // public RigTargets targets; + // public ItemInventoryData invData; + // //public Transform muzzle; + // //public Transform muzzle2; + // //public bool isDoubleBarrel; + + // public FpvTransformRef(RigTargets targets, ItemInventoryData invData) + // { + // this.targets = targets; + // this.invData = invData; + // //this.isDoubleBarrel = isDoubleBarrel; + // fpvAnimator = targets.itemFpv.GetComponentInChildren(); + // //if (isDoubleBarrel) + // //{ + // // muzzle = targets.itemFpv.transform.FindInChildren("Muzzle_L"); + // // muzzle2 = targets.itemFpv.transform.FindInChildren("Muzzle_R"); + // //} + // //else + // // muzzle = targets.itemFpv.transform.FindInChilds("Muzzle"); + // } + + // public bool IsRanged(out ItemActionRanged.ItemActionDataRanged rangedData) + // { + // return (rangedData = invData.actionData[MultiActionManager.GetActionIndexForEntity(GameManager.Instance.World.GetPrimaryPlayer())] as ItemActionRanged.ItemActionDataRanged) != null; + // } + //} + + public static bool IsHoldingRiggedWeapon(EntityPlayer player) + { + AnimationTargetsAbs targets = GetRigTargetsFromPlayer(player); + return targets && !targets.Destroyed; + } + + //private static bool RigItemChangedThisFrame = false; + + //private static readonly HashSet hash_rig_items = new HashSet(); + private static readonly HashSet hash_items_take_over_reload_time = new HashSet(); + private static readonly HashSet hash_items_parse_later = new HashSet(); + private static readonly HashSet hash_rig_names = new HashSet(); + private static readonly HashSet hash_rig_changed_players = new HashSet(); + + //patched to item xml parsing + //public static void AddRigItem(int itemId) => hash_rig_items.Add(itemId); + + public static void Clear() + { + //hash_rig_items.Clear(); + //RigItemChangedThisFrame = false; + hash_items_parse_later.Clear(); + hash_items_take_over_reload_time.Clear(); + hash_rig_names.Clear(); + hash_rig_changed_players.Clear(); + } + + public static void AddReloadTimeTakeOverItem(string name) + { + hash_items_parse_later.Add(name); + } + + public static void AddRigExcludeName(string name) + { + hash_rig_names.Add(name); + } + + public static void RemoveRigExcludeName(string name) + { + hash_rig_names.Remove(name); + } + + public static bool ShouldExcludeRig(string name) + { + return hash_rig_names.Contains(name); + } + + public static string[] GetExcludeRigs() + { + return hash_rig_names.ToArray(); + } + + public static void ParseItemIDs() + { + foreach (var name in hash_items_parse_later) + { + hash_items_take_over_reload_time.Add(ItemClass.GetItemClass(name).Id); + //Log.Out($"parse item id: {name} {ItemClass.GetItemClass(name).Id}"); + } + hash_items_parse_later.Clear(); + } + + public static bool IsReloadTimeTakeOverItem(int id) + { + return hash_items_take_over_reload_time.Contains(id); + } + + public static AnimationTargetsAbs GetRigTargetsFromPlayer(EntityAlive player) + { + if (player is not EntityPlayer) + return null; + Transform holdingItemTransform = player.inventory?.GetHoldingItemTransform(); + if (holdingItemTransform) + { + return holdingItemTransform.GetComponent(); + } + return null; + } + + public static AnimationTargetsAbs GetRigTargetsFromInventory(Inventory inventory) + { + Transform holdingItemTransform = inventory?.GetHoldingItemTransform(); + if (holdingItemTransform) + { + return holdingItemTransform.GetComponent(); + } + return null; + } + + //public static bool IsRigItem(int itemId) => hash_rig_items.Contains(itemId); + + public static void UpdatePlayerAvatar(AvatarController controller) + { + if (!controller?.Entity) + { + return; + } + AnimationTargetsAbs targets = GetRigTargetsFromPlayer(controller.Entity as EntityPlayer); + bool RigItemChangedThisFrame = hash_rig_changed_players.Remove(controller.Entity.entityId); + if (targets && !targets.Destroyed) + { + targets.UpdatePlayerAvatar(controller, RigItemChangedThisFrame); + } + controller.UpdateBool(AvatarController.isCrouchingHash, controller.entity.IsCrouching, true); + //if ((controller.Entity as EntityPlayerLocal).bFirstPersonView && targets && !targets.Destroyed && targets.itemFpv) + //{ + // //workaround for animator bullshit + // if (!targets.itemFpv.gameObject.activeSelf) + // { + // Log.Out("Rigged weapon not active, enabling it..."); + // targets.SetEnabled(true); + // } + // //vroid workaround + // //it seems to use a separate animator for vroid model and does not replace CharacterBody + // //controller.UpdateInt(AvatarController.weaponHoldTypeHash, -1, false); + // controller.FPSArms.Animator.Play("idle", 0, 0f); + // foreach (var hash in resetHashes) + // { + // AnimationRiggingPatches.VanillaResetTrigger(controller, hash, false); + // } + // //controller.FPSArms?.Animator?.SetInteger(AvatarController.weaponHoldTypeHash, -1); + // //controller.CharacterBody?.Animator?.SetInteger(AvatarController.weaponHoldTypeHash, -1); + //} + //if (RigItemChangedThisFrame) + //{ + // Log.Out("Rigged weapon changed, resetting animator..."); + // Transform modelRoot = controller.GetActiveModelRoot(); + // //if (modelRoot && (!targets || targets.Destroyed) && modelRoot.GetComponentInChildren().TryGetComponent(out var builder)) + // //{ + // // builder.DestroyGraph(!targets || targets.Destroyed); + // //} + // if (controller is AvatarLocalPlayerController localPlayerController && localPlayerController.isFPV && localPlayerController.FPSArms != null) + // { + // if (localPlayerController.FPSArms.Animator.TryGetComponent(out var builder)) + // { + // builder.VanillaWrapper.Play("idle", 0, 0f); + // } + // else + // { + // localPlayerController.FPSArms.Animator.Play("idle", 0, 0f); + // } + // } + // controller.UpdateInt(AvatarController.weaponHoldTypeHash, -1, false); + //} + } + + public static void OnClearInventorySlot(Inventory inv, int slot) + { + if (inv == null) + return; + Transform transform = inv.models[slot]; + if (transform && transform.TryGetComponent(out var targets) && !targets.Destroyed) + { + //RigItemChangedThisFrame = true; + targets.Destroy(); + if (slot == inv.holdingItemIdx && inv.entity is EntityPlayer) + { + hash_rig_changed_players.Add(inv.entity.entityId); + } + } + } + + //patched to EntityPlayerLocal.OnHoldingItemChanged and EntityAlive.OnHoldingItemIndexChanged + public static void OnHoldingItemIndexChanged(EntityPlayer player) + { + if (!player || player.inventory == null || player.inventory.m_LastDrawnHoldingItemIndex < 0 || player.inventory.m_LastDrawnHoldingItemIndex >= player.inventory.GetSlotCount()) + return; + if (player.inventory.m_LastDrawnHoldingItemIndex == player.inventory.holdingItemIdx) + { + hash_rig_changed_players.Add(player.entityId); + return; + } + Transform lastHoldingTransform = player.inventory.models[player.inventory.m_LastDrawnHoldingItemIndex]; + if (!lastHoldingTransform) + { + hash_rig_changed_players.Add(player.entityId); + return; + } + AnimationTargetsAbs targets = lastHoldingTransform.GetComponent(); + //if (targets && !targets.Destroyed && targets.IsAnimationSet) + //{ + // //RigItemChangedThisFrame = true; + // hash_rig_changed_players.Add(player.entityId); + // return; + //} + targets = GetRigTargetsFromPlayer(player); + if (targets && !targets.Destroyed && targets.IsAnimationSet) + { + //RigItemChangedThisFrame = true; + hash_rig_changed_players.Add(player.entityId); + } + } + + public static Transform GetAttachmentReferenceOverrideTransform(Transform transform, string transformPath, Entity entity) + { + if (transform == null || entity == null || !(entity is EntityAlive entityAlive) || entityAlive.inventory == null) + return null; + + //Log.Out("TRYING TO REDIRECT TRANSFORM REFERENCE: " + transform.name + " CHILD: " + transformPath); + var targets = entityAlive.inventory.GetHoldingItemTransform()?.GetComponent(); + if (targets != null && targets.attachmentReference != null) + { + var redirected = GameUtils.FindDeepChild(targets.attachmentReference, transform.name) ?? targets.attachmentReference; + //Log.Out("REDIRECTING TRANSFORM REFERENCE TO " + redirected.name); + var find = GameUtils.FindDeepChild(redirected, transformPath); + if (find != null) + //Log.Out("FOUND REDIRECTED CHILD: " + find.name + " PARENT: " + find.parent.name); + return find; + } + + return GameUtils.FindDeepChild(transform, transformPath); + } + + public static Transform GetAttachmentReferenceOverrideTransformActive(Transform transform, string transformPath, Entity entity) + { + if (transform == null || entity == null || !(entity is EntityAlive entityAlive) || entityAlive.inventory == null) + return null; + + //Log.Out("TRYING TO REDIRECT TRANSFORM REFERENCE: " + transform.name + " CHILD: " + transformPath); + var targets = entityAlive.inventory.GetHoldingItemTransform()?.GetComponent(); + if (targets != null && targets.attachmentReference != null) + { + var redirected = GameUtils.FindDeepChildActive(targets.attachmentReference, transform.name) ?? targets.attachmentReference; + //Log.Out("REDIRECTING TRANSFORM REFERENCE TO " + redirected.name); + var find = GameUtils.FindDeepChildActive(redirected, transformPath); + if (find != null) + //Log.Out("FOUND REDIRECTED CHILD: " + find.name + " PARENT: " + find.parent.name); + return find; + } + + return GameUtils.FindDeepChildActive(transform, transformPath); + } + + //public static Transform GetMuzzleOverrideFPV(Transform muzzle, bool isLocalFpv) + //{ + // if (!isLocalFpv || fpvTransformRef == null) + // return muzzle; + // if (fpvTransformRef.IsRanged(out var rangedData)) + // { + // return rangedData.muzzle; + // } + // return muzzle; + //} + + //public static Transform GetMuzzle2OverrideFPV(Transform muzzle2, bool isLocalFpv) + //{ + // if (!isLocalFpv || fpvTransformRef == null) + // return muzzle2; + // if (fpvTransformRef.IsRanged(out var rangedData)) + // { + // return rangedData.muzzle2; + // } + // return muzzle2; + //} + + public static Transform GetTransformOverrideByName(Transform itemModel, string name, bool onlyActive = true) + { + if (itemModel == null) + return null; + if (!itemModel.TryGetComponent(out var targets) || targets.Destroyed) + { + if (string.IsNullOrEmpty(name)) + return itemModel; + return onlyActive ? GameUtils.FindDeepChildActive(itemModel, name) : GameUtils.FindDeepChild(itemModel, name); + } + + Transform targetRoot = targets.ItemCurrentOrDefault; + if (string.IsNullOrEmpty(name)) + return targetRoot; + return onlyActive ? GameUtils.FindDeepChildActive(targetRoot, name) : GameUtils.FindDeepChild(targetRoot, name); + } + + public static Transform GetAddPartTransformOverride(Transform itemModel, string name, bool onlyActive = true) + { + return GetTransformOverrideByName(itemModel, name, onlyActive) ?? itemModel; + } + + //patched to ItemActionRanged.ItemActionEffect + public static bool SpawnFpvParticles(bool isLocalFpv, ItemActionData _actionData, string particlesMuzzleFire, string particlesMuzzleFireFpv, string particlesMuzzleSmoke, string particlesMuzzleSmokeFpv) + { + if (!isLocalFpv || !GetRigTargetsFromInventory(_actionData.invData.holdingEntity.inventory)) + return false; + var itemActionDataRanged = _actionData as ItemActionRanged.ItemActionDataRanged; + EntityPlayerLocal player = GameManager.Instance.World.GetPrimaryPlayer(); + if (itemActionDataRanged.muzzle != null) + { + if (particlesMuzzleFire != null) + { + Transform fire = GameManager.Instance.SpawnParticleEffectClientForceCreation(new ParticleEffect(particlesMuzzleFireFpv != null ? particlesMuzzleFireFpv : particlesMuzzleFire, Vector3.zero, 1f, Color.clear, null, null, false), player.entityId, true); + if (fire != null) + { + fire.transform.localPosition = Vector3.zero; + //fire.transform.localEulerAngles = Vector3.zero; + if (itemActionDataRanged.IsDoubleBarrel && itemActionDataRanged.invData.itemValue.Meta == 0) + fire.transform.SetParent(itemActionDataRanged.muzzle2, false); + else + fire.transform.SetParent(itemActionDataRanged.muzzle, false); + Utils.SetLayerRecursively(fire.gameObject, 10, null); + //fire.transform.localPosition = Vector3.zero; + //fire.transform.localEulerAngles = Vector3.zero; + //fire.transform.localScale = Vector3.one; + foreach (var particle in fire.GetComponentsInChildren()) + { + particle.gameObject.SetActive(true); + particle.Clear(); + particle.Play(); + } + var temp = fire.gameObject.GetOrAddComponent(); + temp.life = 5; + //temp.Restart(); + if (fire.TryGetComponent(out var lod)) + lod.enabled = false; + //Log.Out($"barrel position: {fire.transform.parent.parent.position}/{fire.transform.parent.parent.localPosition}, muzzle position: {fire.transform.parent.position}/{fire.transform.parent.localPosition}, particle position: {fire.transform.position}"); + //Log.Out($"particles: {string.Join("\n", fire.GetComponentsInChildren().Select(ps => ps.name + " active: " + ps.gameObject.activeInHierarchy + " layer: " + ps.gameObject.layer + " position: " + ps.transform.position))}"); + } + } + if (particlesMuzzleSmoke != null && itemActionDataRanged.muzzle != null) + { + float num = GameManager.Instance.World.GetLightBrightness(World.worldToBlockPos(itemActionDataRanged.muzzle.transform.position)) / 2f; + Color clear = Color.clear; + Transform smoke = GameManager.Instance.SpawnParticleEffectClientForceCreation(new ParticleEffect(particlesMuzzleSmokeFpv != null ? particlesMuzzleSmokeFpv : particlesMuzzleSmoke, Vector3.zero, num, clear, null, null, false), player.entityId, true); + if (smoke != null) + { + smoke.transform.localPosition = Vector3.zero; + //smoke.transform.localEulerAngles = Vector3.zero; + Utils.SetLayerRecursively(smoke.gameObject, 10, null); + smoke.transform.SetParent(itemActionDataRanged.muzzle, false); + //smoke.transform.localPosition = Vector3.zero; + //smoke.transform.localEulerAngles = Vector3.zero; + //smoke.transform.localScale = Vector3.one; + foreach (var particle in smoke.GetComponentsInChildren()) + { + particle.gameObject.SetActive(true); + particle.Clear(); + particle.Play(); + } + var temp = smoke.gameObject.GetOrAddComponent(); + temp.life = 5; + //temp.Restart(); + if (smoke.TryGetComponent(out var lod)) + lod.enabled = false; + } + } + } + + return true; + } + + //public static void SetTrigger(int _pid, EntityPlayer player) + //{ + // AnimationTargetsAbs targets = GetRigTargetsFromPlayer(player); + // if (targets && !targets.Destroyed && targets.ItemAnimator) + // { + // targets.ItemAnimator.SetTrigger(_pid); + // //Log.Out($"setting trigger {_pid}"); + // } + //} + + //public static void ResetTrigger(int _pid, EntityPlayer player) + //{ + // AnimationTargetsAbs targets = GetRigTargetsFromPlayer(player); + // if (targets && !targets.Destroyed && targets.ItemAnimator) + // { + // targets.ItemAnimator.ResetTrigger(_pid); + // //Log.Out($"resetting trigger {_pid}"); + // } + //} + + //public static void SetFloat(int _pid, float _value, EntityPlayer player) + //{ + // AnimationTargetsAbs targets = GetRigTargetsFromPlayer(player); + // if (targets&& !targets.Destroyed && targets.ItemAnimator) + // { + // targets.ItemAnimator.SetFloat(_pid, _value); + // //Log.Out($"setting float {_pid}"); + // } + //} + + //public static void SetBool(int _pid, bool _value, EntityPlayer player) + //{ + // AnimationTargetsAbs targets = GetRigTargetsFromPlayer(player); + // if (targets && !targets.Destroyed && targets.ItemAnimator) + // { + // targets.ItemAnimator.SetBool(_pid, _value); + // //Log.Out($"setting bool {_pid}"); + // } + //} + + //public static void SetInt(int _pid, int _value, EntityPlayer player) + //{ + // AnimationTargetsAbs targets = GetRigTargetsFromPlayer(player); + // if (targets && !targets.Destroyed && targets.ItemAnimator) + // { + // targets.ItemAnimator.SetInteger(_pid, _value); + // //Log.Out($"setting int {_pid}"); + // } + //} + } +} diff --git a/Scripts/StaticManagers/BackgroundInventoryUpdateManager.cs b/Scripts/StaticManagers/BackgroundInventoryUpdateManager.cs new file mode 100644 index 0000000..8dc03cd --- /dev/null +++ b/Scripts/StaticManagers/BackgroundInventoryUpdateManager.cs @@ -0,0 +1,117 @@ +using System.Collections.Generic; + +namespace KFCommonUtilityLib.Scripts.StaticManagers +{ + public interface IBackgroundInventoryUpdater + { + int Index { get; } + bool OnUpdate(ItemInventoryData invData); + } + + public static class BackgroundInventoryUpdateManager + { + private static readonly Dictionary[]> dict_updaters = new Dictionary[]>(); + private static readonly Dictionary[]> dict_disabled = new Dictionary[]>(); + + public static void Cleanup() + { + dict_updaters.Clear(); + dict_disabled.Clear(); + } + + public static void RegisterUpdater(EntityAlive entity, int slot, IBackgroundInventoryUpdater updater) + { + //do not handle remote entity update + if (entity == null || entity.isEntityRemote) + return; + + Inventory inv = entity.inventory; + if (inv == null || slot < 0 || slot >= inv.GetSlotCount()) + return; + + if (!dict_updaters.TryGetValue(entity.entityId, out var arr_updaters)) + { + arr_updaters = new List[inv.GetSlotCount()]; + dict_updaters[entity.entityId] = arr_updaters; + } + if (arr_updaters[slot] == null) + { + arr_updaters[slot] = new List(); + } + int lastIndex = arr_updaters[slot].FindIndex(u => u.Index == updater.Index); + if (lastIndex >= 0) + { + //replace old updater, this happens on inventory initialization when player enters game + arr_updaters[slot][lastIndex] = updater; + } + else + { + arr_updaters[slot].Add(updater); + } + } + + public static void DisableUpdater(EntityAlive entity) + { + if (dict_updaters.TryGetValue(entity.entityId, out var updater)) + { + dict_updaters.Remove(entity.entityId); + dict_disabled.Add(entity.entityId, updater); + } + } + + public static void EnableUpdater(EntityAlive entity) + { + if (dict_disabled.TryGetValue(entity.entityId, out var updaters)) + { + dict_disabled.Remove(entity.entityId); + dict_updaters.Add(entity.entityId, updaters); + } + } + + public static void UnregisterUpdater(EntityAlive entity) + { + dict_updaters.Remove(entity.entityId); + } + + public static void UnregisterUpdater(EntityAlive entity, int slot) + { + if (dict_updaters.TryGetValue(entity.entityId, out var arr_updaters) && arr_updaters != null) + { + arr_updaters[slot] = null; + } + } + + public static void Update(EntityAlive entity) + { + if (!entity.isEntityRemote && dict_updaters.TryGetValue(entity.entityId, out var arr_updaters) && arr_updaters != null) + { + Inventory inv = entity.inventory; + int slotCount = inv.GetSlotCount(); + var prevInvData = entity.MinEventContext.ItemInventoryData; + var prevItemValue = entity.MinEventContext.ItemValue; + var prevActionData = entity.MinEventContext.ItemActionData; + bool invChanged = false; + for (int i = 0; i < slotCount; i++) + { + if (arr_updaters[i] != null) + { + foreach (var updater in arr_updaters[i]) + { + if (updater != null) + { + invChanged |= updater.OnUpdate(inv.GetItemDataInSlot(i)); + } + } + } + } + entity.MinEventContext.ItemInventoryData = prevInvData; + entity.MinEventContext.ItemActionData = prevActionData; + entity.MinEventContext.ItemValue = prevItemValue; + if (invChanged) + { + entity.inventory.CallOnToolbeltChangedInternal(); + } + } + } + } +} diff --git a/Scripts/StaticManagers/CustomEffectEnumManager.cs b/Scripts/StaticManagers/CustomEffectEnumManager.cs new file mode 100644 index 0000000..f418b30 --- /dev/null +++ b/Scripts/StaticManagers/CustomEffectEnumManager.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections.Generic; +using UniLinq; + +namespace KFCommonUtilityLib.Scripts.StaticManagers +{ + public static class CustomEffectEnumManager + { + private static event Action OnInitDefault; + private static event Action OnInitFinal; + private static event Action OnPrintResult; + + //call this in InitMod + public static void RegisterEnumType(bool requestMin = false, int requestedMin = 0, bool requestMax = false, int requestedMax = int.MaxValue) where T : struct, Enum + { + if (EnumHolder.Registered) + return; + EnumHolder.Registered = true; + EnumHolder.RequestMinMax(requestMin, requestedMin, requestMax, requestedMax); + OnInitDefault += EnumHolder.InitDefault; + OnInitFinal += EnumHolder.InitFinal; + OnPrintResult += EnumHolder.PrintResult; + } + + //hooked to GameAwake + public static void InitDefault() + { + OnInitDefault?.Invoke(); + } + + //patched to GameManager.StartGame prefix + public static void InitFinal() + { + OnInitFinal?.Invoke(); + } + + public static void PrintResults() + { + OnPrintResult?.Invoke(); + } + + //only call these from callbacks hooked to ModEvents.GameStartDone and cache the results for future usage + //patched to PassiveEffect.ParsePassiveEffect and MinEventActionBase.ParseXmlAttribute + public static T RegisterOrGetEnum(string name, bool ignoreCase = false) where T : struct, Enum + { + if (!EnumHolder.Registered) + { + throw new Exception($"Enum not registered: {typeof(T).Name}"); + } + return EnumHolder.RegisterOrGetEnum(name, ignoreCase); + } + + //public static PassiveEffects RegisterOrGetPassive(string passive) + //{ + // if (!dict_final_passive.TryGetValue(passive, out var value)) + // { + // if (dict_final_passive.Count >= byte.MaxValue) + // throw new OverflowException("Passive effect count exceeds limit 255!"); + // value = (PassiveEffects)(byte)dict_final_passive.Count; + // dict_final_passive.Add(passive, value); + // } + // return value; + //} + + ////patched to MinEventActionBase.ParseXmlAttribute + //public static MinEventTypes RegisterOrGetTrigger(string trigger) + //{ + // if (!dict_final_trigger.TryGetValue(trigger, out var value)) + // { + // value = (MinEventTypes)dict_final_trigger.Count; + // dict_final_trigger.Add(trigger, value); + // } + // return value; + //} + + private static class EnumHolder where T : struct, Enum + { + private static int max, min; + private static readonly TypeCode typecode; + private static readonly Dictionary dict_default_enums = new Dictionary(); + private static readonly Dictionary dict_default_enums_lower = new Dictionary(); + private static readonly LinkedList<(int start, int end)> link_default_holes = new LinkedList<(int start, int end)>(); + private static Dictionary dict_final_enums = new Dictionary(); + private static Dictionary dict_final_enums_lower = new Dictionary(); + private static LinkedList<(int start, int end)> link_final_holes = new LinkedList<(int start, int end)>(); + public static bool Registered { get; set; } = false; + private static bool DefaultInited { get; set; } = false; + static EnumHolder() + { + Type underlying = Enum.GetUnderlyingType(typeof(T)); + typecode = Type.GetTypeCode(underlying); + switch (typecode) + { + case TypeCode.Byte: + min = 0; + max = byte.MaxValue; + break; + case TypeCode.SByte: + min = sbyte.MinValue; + max = sbyte.MaxValue; + break; + case TypeCode.Int16: + min = short.MinValue; + max = short.MaxValue; + break; + case TypeCode.UInt16: + min = 0; + max = ushort.MaxValue; + break; + case TypeCode.Int32: + case TypeCode.Int64: + min = int.MinValue; + max = int.MaxValue; + break; + case TypeCode.UInt32: + case TypeCode.UInt64: + min = 0; + max = int.MaxValue; + break; + default: + throw new Exception($"Invalid underlying type for enum {typeof(T).Name}"); + } + } + + public static void RequestMinMax(bool requestMin, int requestedMin, bool requestMax, int requestedMax) + { + if (requestMin && requestedMin >= min) + { + min = requestedMin; + } + if (requestMax && requestedMax <= max) + { + max = requestedMax; + } + } + + public static void InitDefault() + { + if (DefaultInited) + return; + dict_default_enums.Clear(); + dict_default_enums_lower.Clear(); + link_default_holes.Clear(); + var total = Enum.GetNames(typeof(T)).Length; + var enums = Enum.GetValues(typeof(T)).Cast().ToArray(); + for (int i = 0; i < total; i++) + { + string name = enums[i].ToString(); + dict_default_enums.Add(name, enums[i]); + dict_default_enums_lower.Add(name.ToLower(), enums[i]); + } + var values = enums.Select(e => Convert.ToInt32(e)).OrderBy(i => i).ToArray(); + int nextHole = min; + foreach (var value in values) + { + if (nextHole < value) + { + link_default_holes.AddLast((nextHole, Math.Min(value - 1, max))); + if (value >= max) + { + nextHole = max; + break; + } + nextHole = value + 1; + } + else if (nextHole == value) + { + if (value >= max) + { + break; + } + nextHole++; + } + } + if (nextHole <= max && values[values.Length - 1] < max) + { + link_default_holes.AddLast((nextHole, max)); + } + DefaultInited = true; + } + + public static void InitFinal() + { + dict_final_enums = new Dictionary(dict_default_enums); + dict_final_enums_lower = new Dictionary(dict_default_enums_lower); + link_final_holes = new LinkedList<(int start, int end)>(link_default_holes); + } + + public static void PrintResult() + { + //Log.Out($"{typeof(T).Name}:\n" + string.Join("\n", dict_final_enums.Select(p => $"name: {p.Key} value: {p.Value}"))); + } + + public static T RegisterOrGetEnum(string passive, bool ignoreCase = false) + { + if (!(ignoreCase ? dict_final_enums_lower : dict_final_enums).TryGetValue(ignoreCase ? passive.ToLower() : passive, out var value)) + { + if (link_final_holes.Count == 0) + throw new OverflowException($"Enum count exceeds limit {max}!"); + (int start, int end) = link_final_holes.First.Value; + link_final_holes.RemoveFirst(); + value = (T)Enum.ToObject(typeof(T), Convert.ChangeType(start, typecode)); + dict_final_enums.Add(passive, value); + dict_final_enums_lower.Add(passive.ToLower(), value); + if (start < end) + { + start++; + link_final_holes.AddFirst((start, end)); + } + } + return value; + } + } + } +} diff --git a/Scripts/StaticManagers/DelayLoadModuleManager.cs b/Scripts/StaticManagers/DelayLoadModuleManager.cs new file mode 100644 index 0000000..0b1a39a --- /dev/null +++ b/Scripts/StaticManagers/DelayLoadModuleManager.cs @@ -0,0 +1,95 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using UniLinq; + +namespace KFCommonUtilityLib.Scripts.StaticManagers +{ + public static class DelayLoadModuleManager + { + private static readonly List<(string mod, List dlls)> list_delay_load = new List<(string mod, List dlls)>(); + + private static readonly List loaded = new List(); + + public static void RegisterDelayloadDll(string modName, string dllNameWithoutExtension) + { + List dlls; + int index = list_delay_load.FindIndex(p => p.mod == modName); + if (index < 0) + { + dlls = new List() { dllNameWithoutExtension }; + list_delay_load.Add((modName, dlls)); + return; + } + dlls = list_delay_load[index].dlls; + dlls.Add(dllNameWithoutExtension); + } + + public static void DelayLoad() + { + Assembly assembly = Assembly.GetAssembly(typeof(DelayLoadModuleManager)); + Mod mod = ModManager.GetModForAssembly(assembly); + string delayLoadFolder = mod.Path + "/DelayLoad"; + ModuleManagers.AddAssemblySearchPath(delayLoadFolder); + foreach (var pair in list_delay_load) + { + if (ModManager.GetLoadedAssemblies().Any(a => a.GetName().Name == pair.mod)) + { + foreach (var dll in pair.dlls) + { + try + { + string assPath = Path.GetFullPath(delayLoadFolder + $"/{dll}.dll"); + Assembly patch = Assembly.LoadFrom(assPath); + if (Path.GetFullPath(patch.Location).Equals(assPath, StringComparison.OrdinalIgnoreCase)) + { + foreach (var type in patch.GetTypes()) + { + if (typeof(IModApi).IsAssignableFrom(type)) + { + IModApi modApi = (IModApi)Activator.CreateInstance(type); + modApi.InitMod(mod); + Log.Out(string.Concat($"[DELAYLOAD] Initialized code in {dll}.dll")); + } + } + mod.allAssemblies.Add(patch); + } + } + catch (Exception ex) + { + Log.Error($"[DELAYLOAD] Failed loading DLL {dll}.dll"); + Log.Exception(ex); + } + } + } + } + //if (ModManager.GetLoadedAssemblies().FirstOrDefault(a => a.GetName().Name == "FullautoLauncher") != null) + //{ + // try + // { + // string assPath = Path.GetFullPath(delayLoadFolder + "/FullautoLauncherAnimationRiggingCompatibilityPatch.dll"); + // Assembly patch = Assembly.LoadFrom(assPath); + // if (Path.GetFullPath(patch.Location).Equals(assPath, StringComparison.OrdinalIgnoreCase)) + // { + // Type apiType = typeof(IModApi); + // foreach (var type in patch.GetTypes()) + // { + // if (apiType.IsAssignableFrom(type)) + // { + // IModApi modApi = (IModApi)Activator.CreateInstance(type); + // modApi.InitMod(mod); + // Log.Out(string.Concat("[DELAYLOAD] Initialized code in FullautoLauncherAnimationRiggingCompatibilityPatch.dll")); + // } + // } + // } + // } + // catch (Exception ex) + // { + // Log.Error("[DELAYLOAD] Failed loading DLL FullautoLauncherAnimationRiggingCompatibilityPatch.dll"); + // Log.Exception(ex); + // } + //} + } + } +} diff --git a/Scripts/StaticManagers/ItemActionModuleManager.cs b/Scripts/StaticManagers/ItemActionModuleManager.cs new file mode 100644 index 0000000..69f7a66 --- /dev/null +++ b/Scripts/StaticManagers/ItemActionModuleManager.cs @@ -0,0 +1,937 @@ +using HarmonyLib; +using KFCommonUtilityLib.Harmony; +using KFCommonUtilityLib.Scripts.Attributes; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Security.Permissions; +using System.Text; +using UniLinq; +using UnityEngine; +using UnityEngine.Scripting; +using FieldAttributes = Mono.Cecil.FieldAttributes; +using MethodAttributes = Mono.Cecil.MethodAttributes; +using MethodBody = Mono.Cecil.Cil.MethodBody; +using TypeAttributes = Mono.Cecil.TypeAttributes; + +namespace KFCommonUtilityLib.Scripts.StaticManagers +{ + //public static class AssemblyLocator + //{ + // private static Dictionary assemblies; + + // public static void Init() + // { + // assemblies = new Dictionary(); + // foreach (var assembly in ModManager.GetLoadedAssemblies()) + // { + // assemblies.Add(assembly.FullName, assembly); + // } + // AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(CurrentDomain_AssemblyLoad); + // AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); + // } + + // private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) + // { + // assemblies.TryGetValue(args.Name, out Assembly assembly); + // if (assembly != null) + // Log.Out($"RESOLVING ASSEMBLY {assembly.FullName}"); + // else + // Log.Error($"RESOLVING ASSEMBBLY {args.Name} FAILED!"); + // return assembly; + // } + + // private static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args) + // { + // Assembly assembly = args.LoadedAssembly; + // assemblies[assembly.FullName] = assembly; + // Log.Out($"LOADING ASSEMBLY {assembly.FullName}"); + // } + //} + + public interface IModuleContainerFor where T : class + { + T Instance { get; } + } + + public class MethodPatchInfo + { + public readonly MethodDefinition Method; + public Instruction PrefixBegin; + public Instruction PostfixBegin; + public Instruction PostfixEnd; + + public MethodPatchInfo(MethodDefinition mtddef, Instruction postfixEnd, Instruction prefixBegin) + { + Method = mtddef; + PostfixEnd = postfixEnd; + PrefixBegin = prefixBegin; + } + } + + public static class ItemActionModuleManager + { + private static readonly List list_created = new List(); + private static AssemblyDefinition workingAssembly = null; + private static DefaultAssemblyResolver resolver; + private static ModuleAttributes moduleAttributes; + private static ModuleCharacteristics moduleCharacteristics; + private static readonly Dictionary> dict_replacement_mapping = new Dictionary>(); + + internal static void ClearOutputFolder() + { + Mod self = ModManager.GetMod("CommonUtilityLib"); + string path = Path.Combine(self.Path, "AssemblyOutput"); + if (Directory.Exists(path)) + Array.ForEach(Directory.GetFiles(path), File.Delete); + else + Directory.CreateDirectory(path); + } + + internal static void InitNew() + { + dict_replacement_mapping.Clear(); + workingAssembly?.Dispose(); + if (resolver == null) + { + resolver = new DefaultAssemblyResolver(); + resolver.AddSearchDirectory(Path.Combine(Application.dataPath, "Managed")); + + foreach (var mod in ModManager.GetLoadedMods()) + { + resolver.AddSearchDirectory(mod.Path); + } + + AssemblyDefinition assdef_main = AssemblyDefinition.ReadAssembly($"{Application.dataPath}/Managed/Assembly-CSharp.dll", new ReaderParameters() { AssemblyResolver = resolver }); + moduleAttributes = assdef_main.MainModule.Attributes; + moduleCharacteristics = assdef_main.MainModule.Characteristics; + Log.Out("Reading Attributes from assembly: " + assdef_main.FullName); + } + string assname = "ItemActionModule" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + workingAssembly = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition(assname, + new Version(0, 0, 0, 0)), + assname + ".dll", + new ModuleParameters() + { + Kind = ModuleKind.Dll, + AssemblyResolver = resolver, + Architecture = TargetArchitecture.I386, + Runtime = TargetRuntime.Net_4_0, + }); + workingAssembly.MainModule.Attributes = moduleAttributes; + workingAssembly.MainModule.Characteristics = moduleCharacteristics; + //write security attributes so that calling non-public patch methods from this assembly is allowed + Mono.Cecil.SecurityAttribute sattr_permission = new Mono.Cecil.SecurityAttribute(workingAssembly.MainModule.ImportReference(typeof(SecurityPermissionAttribute))); + Mono.Cecil.CustomAttributeNamedArgument caarg_SkipVerification = new Mono.Cecil.CustomAttributeNamedArgument(nameof(SecurityPermissionAttribute.SkipVerification), new CustomAttributeArgument(workingAssembly.MainModule.TypeSystem.Boolean, true)); + sattr_permission.Properties.Add(caarg_SkipVerification); + SecurityDeclaration sdec = new SecurityDeclaration(Mono.Cecil.SecurityAction.RequestMinimum); + sdec.SecurityAttributes.Add(sattr_permission); + workingAssembly.SecurityDeclarations.Add(sdec); + Log.Out("======Init New======"); + } + + internal static void CheckItem(ItemClass item) + { + for (int i = 0; i < item.Actions.Length; i++) + { + ItemAction itemAction = item.Actions[i]; + if (itemAction != null && itemAction.Properties.Values.TryGetValue("ItemActionModules", out string str_modules)) + { + string[] modules = str_modules.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + Type itemActionType = itemAction.GetType(); + Type[] moduleTypes = modules.Select(s => ReflectionHelpers.GetTypeWithPrefix("ActionModule", s.Trim())) + .Where(t => t.GetCustomAttribute().BaseType.IsAssignableFrom(itemActionType)).ToArray(); + string typename = CreateTypeName(itemActionType, moduleTypes); + //Log.Out(typename); + if (!TryFindType(typename, out _) && !TryFindInCur(typename, out _)) + PatchType(itemActionType, moduleTypes); + if (!dict_replacement_mapping.TryGetValue(item.Name, out var list)) + { + list = new List<(string typename, int indexOfAction)>(); + dict_replacement_mapping.Add(item.Name, list); + } + list.Add((typename, i)); + } + } + } + + internal static void FinishAndLoad() + { + //output assembly + Log.Out("======Finish and Load======"); + Mod self = ModManager.GetMod("CommonUtilityLib"); + if (self == null) + { + Log.Warning("Failed to get mod!"); + self = ModManager.GetModForAssembly(typeof(ItemActionModuleManager).Assembly); + } + if (self != null && workingAssembly != null && workingAssembly.MainModule.Types.Count > 1) + { + Log.Out("Assembly is valid!"); + using (MemoryStream ms = new MemoryStream()) + { + try + { + workingAssembly.Write(ms); + } + catch (Exception) + { + new ConsoleCmdShutdown().Execute(new List(), new CommandSenderInfo()); + } + DirectoryInfo dirInfo = Directory.CreateDirectory(Path.Combine(self.Path, "AssemblyOutput")); + string filename = Path.Combine(dirInfo.FullName, workingAssembly.Name.Name + ".dll"); + Log.Out("Output Assembly: " + filename); + using (FileStream fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write)) + { + ms.WriteTo(fs); + } + Assembly newAssembly = Assembly.LoadFile(filename); + list_created.Add(newAssembly); + } + } + + //replace item actions + if (list_created.Count > 0) + { + foreach (var pair in dict_replacement_mapping) + { + ItemClass item = ItemClass.GetItemClass(pair.Key, true); + foreach ((string typename, int indexOfAction) in pair.Value) + { + if (TryFindType(typename, out Type itemActionType)) + { + //Log.Out($"Replace ItemAction {item.Actions[indexOfAction].GetType().FullName} with {itemActionType.FullName}"); + ItemAction itemActionPrev = item.Actions[indexOfAction]; + item.Actions[indexOfAction] = (ItemAction)Activator.CreateInstance(itemActionType); + item.Actions[indexOfAction].ActionIndex = indexOfAction; + item.Actions[indexOfAction].item = item; + item.Actions[indexOfAction].ExecutionRequirements = itemActionPrev.ExecutionRequirements; + item.Actions[indexOfAction].ReadFrom(itemActionPrev.Properties); + } + } + } + } + + //cleanup + workingAssembly?.Dispose(); + workingAssembly = null; + dict_replacement_mapping.Clear(); + } + + private static void PatchType(Type itemActionType, params Type[] moduleTypes) + { + if (workingAssembly == null) + return; + + //Get assembly module + ModuleDefinition module = workingAssembly.MainModule; + + TypeReference typeref_interface = module.ImportReference(typeof(IModuleContainerFor<>)); + //Prepare type info + TypeTargetAttribute[] arr_attr_modules = moduleTypes.Select(t => t.GetCustomAttribute()).ToArray(); + TypeReference[] arr_typeref_modules = moduleTypes.Select(t => module.ImportReference(t)).ToArray(); + Type[] arr_type_data = arr_attr_modules.Select(a => a.DataType).ToArray(); + TypeReference[] arr_typeref_data = arr_type_data.Select(a => a != null ? module.ImportReference(a) : null).ToArray(); + + //Find ItemActionData subtype + MethodInfo mtdinf_create_data = null; + { + Type type_itemActionRoot = typeof(ItemAction); + Type type_itemActionBase = itemActionType; + while (typeof(ItemAction).IsAssignableFrom(type_itemActionBase)) + { + mtdinf_create_data = type_itemActionBase.GetMethod(nameof(ItemAction.CreateModifierData), BindingFlags.Public | BindingFlags.Instance); + if (mtdinf_create_data != null) + break; + mtdinf_create_data = mtdinf_create_data.GetBaseDefinition(); + } + } + + //Create new ItemAction + TypeReference typeref_itemAction = module.ImportReference(itemActionType); + TypeDefinition typedef_newAction = new TypeDefinition(null, CreateTypeName(itemActionType, moduleTypes), TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.Public | TypeAttributes.Sealed, typeref_itemAction); + for (int i = 0; i < arr_typeref_modules.Length; i++) + { + + + } + typedef_newAction.CustomAttributes.Add(new CustomAttribute(module.ImportReference(typeof(PreserveAttribute).GetConstructor(Array.Empty())))); + module.Types.Add(typedef_newAction); + + //Create new ItemActionData + //Find CreateModifierData + MethodDefinition mtddef_create_data = module.ImportReference(mtdinf_create_data).Resolve(); + //ItemActionData subtype is the return type of CreateModifierData + TypeReference typeref_actiondata = ((MethodReference)mtddef_create_data.Body.Instructions[mtddef_create_data.Body.Instructions.Count - 2].Operand).DeclaringType; + //Get type by assembly qualified name since it might be from mod assembly + Type type_itemActionData = Type.GetType(Assembly.CreateQualifiedName(typeref_actiondata.Module.Assembly.Name.Name, typeref_actiondata.FullName)); + TypeDefinition typedef_newActionData = new TypeDefinition(null, CreateTypeName(type_itemActionData, arr_type_data), TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.NestedPublic | TypeAttributes.Sealed, module.ImportReference(typeref_actiondata)); + typedef_newActionData.CustomAttributes.Add(new CustomAttribute(module.ImportReference(typeof(PreserveAttribute).GetConstructor(Array.Empty())))); + typedef_newAction.NestedTypes.Add(typedef_newActionData); + + //Create fields + FieldDefinition[] arr_flddef_modules = new FieldDefinition[moduleTypes.Length]; + FieldDefinition[] arr_flddef_data = new FieldDefinition[moduleTypes.Length]; + for (int i = 0; i < moduleTypes.Length; i++) + { + //Create ItemAction field + Type type_module = moduleTypes[i]; + FieldDefinition flddef_module = new FieldDefinition(CreateFieldName(type_module), FieldAttributes.Public, arr_typeref_modules[i]); + typedef_newAction.Fields.Add(flddef_module); + arr_flddef_modules[i] = flddef_module; + + TypeReference typeref_module = arr_typeref_modules[i]; + MakeContainerFor(module, typeref_interface, typedef_newAction, type_module, flddef_module, typeref_module); + + //Create ItemActionData field + if (arr_typeref_data[i] != null) + { + TypeReference typeref_data = arr_typeref_data[i]; + Type type_data = arr_type_data[i]; + FieldDefinition flddef_data = new FieldDefinition(CreateFieldName(type_data), FieldAttributes.Public, typeref_data); + typedef_newActionData.Fields.Add(flddef_data); + arr_flddef_data[i] = flddef_data; + + MakeContainerFor(module, typeref_interface, typedef_newActionData, type_data, flddef_data, typeref_data); + } + } + + //Create ItemAction constructor + MethodDefinition mtddef_ctor = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, module.TypeSystem.Void); + var il = mtddef_ctor.Body.GetILProcessor(); + il.Append(il.Create(OpCodes.Ldarg_0)); + il.Append(il.Create(OpCodes.Call, module.ImportReference(itemActionType.GetConstructor(Array.Empty())))); + il.Append(il.Create(OpCodes.Nop)); + for (int i = 0; i < arr_flddef_modules.Length; i++) + { + il.Append(il.Create(OpCodes.Ldarg_0)); + il.Append(il.Create(OpCodes.Newobj, module.ImportReference(moduleTypes[i].GetConstructor(Array.Empty())))); + il.Append(il.Create(OpCodes.Stfld, arr_flddef_modules[i])); + il.Append(il.Create(OpCodes.Nop)); + } + il.Append(il.Create(OpCodes.Ret)); + typedef_newAction.Methods.Add(mtddef_ctor); + + //Create ItemActionData constructor + MethodDefinition mtddef_ctor_data = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, module.TypeSystem.Void); + mtddef_ctor_data.Parameters.Add(new ParameterDefinition("_inventoryData", Mono.Cecil.ParameterAttributes.None, module.ImportReference(typeof(ItemInventoryData)))); + mtddef_ctor_data.Parameters.Add(new ParameterDefinition("_indexInEntityOfAction", Mono.Cecil.ParameterAttributes.None, module.TypeSystem.Int32)); + FieldReference fldref_invdata_item = module.ImportReference(typeof(ItemInventoryData).GetField(nameof(ItemInventoryData.item))); + FieldReference fldref_item_actions = module.ImportReference(typeof(ItemClass).GetField(nameof(ItemClass.Actions))); + il = mtddef_ctor_data.Body.GetILProcessor(); + il.Append(il.Create(OpCodes.Ldarg_0)); + il.Append(il.Create(OpCodes.Ldarg_1)); + il.Append(il.Create(OpCodes.Ldarg_2)); + il.Append(il.Create(OpCodes.Call, module.ImportReference(type_itemActionData.GetConstructor(new Type[] { typeof(ItemInventoryData), typeof(int) })))); + il.Append(il.Create(OpCodes.Nop)); + for (int i = 0; i < arr_flddef_data.Length; i++) + { + if (arr_type_data[i] == null) + continue; + il.Append(il.Create(OpCodes.Ldarg_0)); + il.Append(il.Create(OpCodes.Ldarg_1)); + il.Append(il.Create(OpCodes.Ldarg_2)); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldfld, fldref_invdata_item); + il.Emit(OpCodes.Ldfld, fldref_item_actions); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Ldelem_Ref); + il.Emit(OpCodes.Castclass, typedef_newAction); + il.Emit(OpCodes.Ldfld, arr_flddef_modules[i]); + il.Append(il.Create(OpCodes.Newobj, module.ImportReference(arr_type_data[i].GetConstructor(new Type[] { typeof(ItemInventoryData), typeof(int), moduleTypes[i] })))); + il.Append(il.Create(OpCodes.Stfld, arr_flddef_data[i])); + il.Append(il.Create(OpCodes.Nop)); + } + il.Append(il.Create(OpCodes.Ret)); + typedef_newActionData.Methods.Add(mtddef_ctor_data); + + //Create ItemAction.CreateModifierData override + MethodDefinition mtddef_create_modifier_data = new MethodDefinition(nameof(ItemAction.CreateModifierData), MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot, module.ImportReference(typeof(ItemActionData))); + mtddef_create_modifier_data.Parameters.Add(new ParameterDefinition("_invData", Mono.Cecil.ParameterAttributes.None, module.ImportReference(typeof(ItemInventoryData)))); + mtddef_create_modifier_data.Parameters.Add(new ParameterDefinition("_indexInEntityOfAction", Mono.Cecil.ParameterAttributes.None, module.TypeSystem.Int32)); + il = mtddef_create_modifier_data.Body.GetILProcessor(); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Newobj, mtddef_ctor_data); + il.Emit(OpCodes.Ret); + typedef_newAction.Methods.Add(mtddef_create_modifier_data); + + // + Dictionary dict_overrides = new Dictionary(); + // + Dictionary list_mtdinf_patches)>> dict_transpilers = new Dictionary list_mtdinf_patches)>>(); + //> + Dictionary> dict_all_states = new Dictionary>(); + + //Get all transpilers and clone original methods + for (int i = 0; i < moduleTypes.Length; i++) + { + Type moduleType = moduleTypes[i]; + const BindingFlags searchFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; + foreach (var mtd in moduleType.GetMethods(searchFlags)) + { + var attr = mtd.GetCustomAttribute(); + if (attr != null) + { + string id = attr.GetTargetMethodIdentifier(); + if (!dict_transpilers.TryGetValue(id, out var list_transpilers)) + { + list_transpilers = new List<(MethodDefinition mtddef_target, MethodReference mtdref_original, MethodReference mtdref_harmony, List list_mtdinf_patches)> { }; + dict_transpilers[id] = list_transpilers; + } + int maxLevels = 0; + Type nextType = itemActionType; + while (attr.PreferredType.IsAssignableFrom(nextType)) + { + maxLevels++; + if (list_transpilers.Count < maxLevels) + { + var mtdinfo_cur = AccessTools.Method(nextType, attr.TargetMethod, attr.Params); + var mtdinfo_harmony = ItemActionModulePatch.GetRealMethod(mtdinfo_cur, true); + //transpilers on undeclared methods are invalid + var mtdref_original = mtdinfo_cur.DeclaringType.Equals(nextType) ? module.ImportReference(mtdinfo_cur) : null; + var mtdref_harmony = mtdref_original != null ? module.ImportReference(mtdinfo_harmony) : null; + var mtddef_copy = mtdref_harmony?.Resolve()?.CloneToModuleAsStatic(module.ImportReference(mtdinfo_cur.DeclaringType), module) ?? null; + list_transpilers.Add((mtddef_copy, mtdref_original, mtdref_harmony, new List())); + } + nextType = nextType.BaseType; + } + list_transpilers[maxLevels - 1].list_mtdinf_patches.Add(mtd); + } + } + } + + //apply transpilers and replace method calls on base methods with patched ones + Dictionary dict_replacers = new Dictionary(); + foreach (var pair in dict_transpilers) + { + //the top copy to call in the override method + MethodDefinition mtddef_override_copy = null; + MethodReference mtdref_override_base = null; + for (int i = pair.Value.Count - 1; i >= 0; i--) + { + var mtddef_target = pair.Value[i].mtddef_target; + var mtdref_original = pair.Value[i].mtdref_harmony; + if (mtddef_target != null) + { + foreach (var patch in pair.Value[i].list_mtdinf_patches) + { + mtddef_target.Body.SimplifyMacros(); + patch.Invoke(null, new object[] { mtddef_target.Body, module }); + mtddef_target.Body.OptimizeMacros(); + } + + if (i < pair.Value.Count - 1) + { + //find first available base method + MethodDefinition mtddef_base_target = null; + MethodReference mtdref_base_original = null; + for (int j = i + 1; j < pair.Value.Count; j++) + { + mtddef_base_target = pair.Value[j].mtddef_target; + mtdref_base_original = pair.Value[j].mtdref_original; + if (mtddef_base_target != null) + { + break; + } + } + //replace calls to the base + if (mtddef_base_target != null) + { + foreach (var ins in mtddef_target.Body.Instructions) + { + if (ins.OpCode == OpCodes.Call && ((MethodReference)ins.Operand).FullName.Equals(mtdref_base_original.FullName)) + { + Log.Out($"replacing call to {mtdref_base_original.FullName} to {mtddef_base_target.FullName}"); + ins.Operand = mtddef_base_target; + } + } + } + } + //the iteration is reversed so make sure we grab the latest method + if (mtddef_target != null) + { + mtddef_override_copy = mtddef_target; + mtdref_override_base = mtdref_original; + } + //add patched copy to the class + typedef_newAction.Methods.Add(mtddef_target); + } + } + //create the method override that calls the patched copy + GetOrCreateOverride(dict_overrides, pair.Key, mtdref_override_base, module, mtddef_override_copy); + } + + //Apply Postfixes first so that Prefixes can jump to the right instruction + for (int i = 0; i < moduleTypes.Length; i++) + { + Type moduleType = moduleTypes[i]; + Dictionary dict_targets = GetMethodOverrideTargets(itemActionType, moduleType, module); + string moduleID = CreateFieldName(moduleType); + foreach (var pair in dict_targets) + { + MethodDefinition mtddef_root = module.ImportReference(pair.Value.mtdinf_base.GetBaseDefinition()).Resolve(); + MethodDefinition mtddef_target = module.ImportReference(pair.Value.mtdinf_target).Resolve(); + MethodPatchInfo mtdpinf_derived = GetOrCreateOverride(dict_overrides, pair.Key, pair.Value.mtdref_base, module); + MethodDefinition mtddef_derived = mtdpinf_derived.Method; + + if (!dict_all_states.TryGetValue(pair.Key, out var dict_states)) + { + dict_states = new Dictionary(); + dict_all_states.Add(pair.Key, dict_states); + } + var list_inst_pars = MatchArguments(mtddef_root, mtdpinf_derived, mtddef_target, arr_flddef_modules[i], arr_flddef_data[i], module, itemActionType, typedef_newActionData, true, dict_states, moduleID); + //insert invocation + il = mtddef_derived.Body.GetILProcessor(); + foreach (var ins in list_inst_pars) + { + il.InsertBefore(mtdpinf_derived.PostfixEnd, ins); + } + il.InsertBefore(mtdpinf_derived.PostfixEnd, il.Create(OpCodes.Call, module.ImportReference(mtddef_target))); + if (mtdpinf_derived.PostfixBegin == null) + mtdpinf_derived.PostfixBegin = list_inst_pars[0]; + } + } + + //Apply Prefixes + for (int i = moduleTypes.Length - 1; i >= 0; i--) + { + Type moduleType = moduleTypes[i]; + Dictionary dict_targets = GetMethodOverrideTargets(itemActionType, moduleType, module); + string moduleID = CreateFieldName(moduleType); + foreach (var pair in dict_targets) + { + MethodDefinition mtddef_root = module.ImportReference(pair.Value.mtdinf_base.GetBaseDefinition()).Resolve(); + MethodDefinition mtddef_target = module.ImportReference(pair.Value.mtdinf_target).Resolve(); + MethodPatchInfo mtdpinf_derived = GetOrCreateOverride(dict_overrides, pair.Key, pair.Value.mtdref_base, module); + MethodDefinition mtddef_derived = mtdpinf_derived.Method; + dict_all_states.TryGetValue(pair.Key, out var dict_states); + var list_inst_pars = MatchArguments(mtddef_root, mtdpinf_derived, mtddef_target, arr_flddef_modules[i], arr_flddef_data[i], module, itemActionType, typedef_newActionData, false, dict_states, moduleID); + //insert invocation + il = mtdpinf_derived.Method.Body.GetILProcessor(); + Instruction ins_insert = mtdpinf_derived.PrefixBegin; + foreach (var ins in list_inst_pars) + { + il.InsertBefore(ins_insert, ins); + } + il.InsertBefore(ins_insert, il.Create(OpCodes.Call, module.ImportReference(mtddef_target))); + il.InsertBefore(ins_insert, il.Create(OpCodes.Brfalse_S, mtdpinf_derived.PostfixBegin ?? mtdpinf_derived.PostfixEnd)); + } + } + + foreach (var pair in dict_all_states) + { + var dict_states = pair.Value; + if (dict_states.Count > 0) + { + Log.Error($"__state variable count does not match in prefixes and postfixes for {pair.Key}! check following modules:\n" + string.Join("\n", dict_states.Keys)); + throw new Exception(); + } + } + + //Add all overrides to new type + foreach (var mtd in dict_overrides.Values) + { + typedef_newAction.Methods.Add(mtd.Method); + + //Log.Out($"Add method override to new action: {mtd.Method.Name}"); + } + } + + private static void MakeContainerFor(ModuleDefinition module, TypeReference typeref_interface, TypeDefinition typedef_container, Type type_module, FieldDefinition flddef_module, TypeReference typeref_module) + { + typedef_container.Interfaces.Add(new InterfaceImplementation(typeref_interface.MakeGenericInstanceType(typeref_module))); + PropertyDefinition propdef_instance = new PropertyDefinition("Instance", Mono.Cecil.PropertyAttributes.None, typeref_module); + MethodDefinition mtddef_instance_getter = new MethodDefinition("get_Instance", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, typeref_module); + mtddef_instance_getter.Overrides.Add(module.ImportReference(AccessTools.Method(typeof(IModuleContainerFor<>).MakeGenericType(type_module), "get_Instance"))); + typedef_container.Methods.Add(mtddef_instance_getter); + mtddef_instance_getter.Body = new Mono.Cecil.Cil.MethodBody(mtddef_instance_getter); + var generator = mtddef_instance_getter.Body.GetILProcessor(); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldfld, flddef_module); + generator.Emit(OpCodes.Ret); + propdef_instance.GetMethod = mtddef_instance_getter; + typedef_container.Properties.Add(propdef_instance); + } + + /// + /// + /// + /// + /// + /// + /// + /// + private static Dictionary GetMethodOverrideTargets(Type itemActionType, Type moduleType, ModuleDefinition module) where T : Attribute, IMethodTarget + { + Dictionary dict_overrides = new Dictionary(); + const BindingFlags searchFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + foreach (var mtd in moduleType.GetMethods(searchFlags)) + { + IMethodTarget attr = mtd.GetCustomAttribute(); + if (attr != null && (attr.PreferredType == null || attr.PreferredType.IsAssignableFrom(itemActionType))) + { + string id = attr.GetTargetMethodIdentifier(); + MethodInfo mtdinf_base = AccessTools.Method(itemActionType, attr.TargetMethod, attr.Params); + if (mtdinf_base == null || !mtdinf_base.IsVirtual || mtdinf_base.IsFinal) + { + Log.Error($"Method not found: {attr.TargetMethod}"); + continue; + } + + MethodReference mtdref_base = module.ImportReference(mtdinf_base); + //Find preferred patch + if (dict_overrides.TryGetValue(id, out var pair)) + { + if (attr.PreferredType == null) + continue; + //cur action type is sub or same class of cur preferred type + //cur preferred type is sub class of previous preferred type + //means cur preferred type is closer to the action type in inheritance hierachy than the previous one + if (attr.PreferredType.IsAssignableFrom(itemActionType) && (pair.prefType == null || attr.PreferredType.IsSubclassOf(pair.prefType))) + { + dict_overrides[id] = new MethodOverrideInfo(mtd, mtdinf_base, mtdref_base, attr.PreferredType); + } + } + else + { + dict_overrides[id] = new MethodOverrideInfo(mtd, mtdinf_base, mtdref_base, attr.PreferredType); + } + //Log.Out($"Add method override: {id} for {mtdref_base.FullName}/{mtdinf_base.Name}, action type: {itemActionType.Name}"); + } + else + { + //Log.Out($"No override target found or preferred type not match on {mtd.Name}"); + } + } + return dict_overrides; + } + + /// + /// Get or create override MethodDefinition of mtdref_base. + /// + /// + /// + /// + /// + /// + private static MethodPatchInfo GetOrCreateOverride(Dictionary dict_overrides, string id, MethodReference mtdref_base, ModuleDefinition module, MethodDefinition mtddef_base_override = null) + { + //if (mtddef_base.FullName == "CreateModifierData") + // throw new MethodAccessException($"YOU SHOULD NOT MANUALLY MODIFY CreateModifierData!"); + if (dict_overrides.TryGetValue(id, out var mtdpinf_derived)) + { + return mtdpinf_derived; + } + //when overriding, retain attributes of base but make sure to remove the 'new' keyword which presents if you are overriding the root method + MethodDefinition mtddef_derived = new MethodDefinition(mtdref_base.Name, (mtdref_base.Resolve().Attributes | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot) & ~MethodAttributes.NewSlot, module.ImportReference(mtdref_base.ReturnType)); + + //Log.Out($"Create method override: {id} for {mtdref_base.FullName}"); + foreach (var par in mtdref_base.Parameters) + { + ParameterDefinition pardef = new ParameterDefinition(par.Name, par.Attributes, module.ImportReference(par.ParameterType)); + if (par.HasConstant) + pardef.Constant = par.Constant; + mtddef_derived.Parameters.Add(pardef); + } + mtddef_derived.Body.Variables.Clear(); + mtddef_derived.Body.InitLocals = true; + mtddef_derived.Body.Variables.Add(new VariableDefinition(module.TypeSystem.Boolean)); + bool hasReturnVal = mtddef_derived.ReturnType.MetadataType != MetadataType.Void; + if (hasReturnVal) + { + mtddef_derived.Body.Variables.Add(new VariableDefinition(module.ImportReference(mtdref_base.ReturnType))); + } + var il = mtddef_derived.Body.GetILProcessor(); + if (hasReturnVal) + { + il.Emit(OpCodes.Ldloca_S, mtddef_derived.Body.Variables[1]); + il.Emit(OpCodes.Initobj, module.ImportReference(mtddef_derived.ReturnType)); + } + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Stloc_S, mtddef_derived.Body.Variables[0]); + Instruction prefixBegin = il.Create(OpCodes.Ldc_I4_1); + il.Append(prefixBegin); + il.Emit(OpCodes.Stloc_S, mtddef_derived.Body.Variables[0]); + il.Emit(OpCodes.Ldarg_0); + for (int i = 0; i < mtddef_derived.Parameters.Count; i++) + { + var par = mtddef_derived.Parameters[i]; + il.Emit(par.ParameterType.IsByReference ? OpCodes.Ldarga_S : OpCodes.Ldarg_S, par); + } + il.Emit(OpCodes.Call, mtddef_base_override ?? module.ImportReference(mtdref_base)); + if (hasReturnVal) + { + il.Emit(OpCodes.Stloc_S, mtddef_derived.Body.Variables[1]); + il.Emit(OpCodes.Ldloc_S, mtddef_derived.Body.Variables[1]); + } + il.Emit(OpCodes.Ret); + mtdpinf_derived = new MethodPatchInfo(mtddef_derived, mtddef_derived.Body.Instructions[mtddef_derived.Body.Instructions.Count - (hasReturnVal ? 2 : 1)], prefixBegin); + dict_overrides.Add(id, mtdpinf_derived); + return mtdpinf_derived; + } + + /// + /// Create a List that loads all arguments required to call the method onto stack. + /// + /// The override method. + /// The patch method to be called. + /// The injected module field. + /// The injected data field. + /// The assembly's main module. + /// The base ItemAction type. + /// + /// + /// + /// + private static List MatchArguments(MethodDefinition mtddef_root, MethodPatchInfo mtdpinf_derived, MethodDefinition mtddef_target, FieldDefinition flddef_module, FieldDefinition flddef_data, ModuleDefinition module, Type itemActionType, TypeDefinition typedef_newactiondata, bool isPostfix, Dictionary dict_states, string moduleID) + { + var mtddef_derived = mtdpinf_derived.Method; + var il = mtddef_derived.Body.GetILProcessor(); + //Match parameters + List list_inst_pars = new List(); + list_inst_pars.Add(il.Create(OpCodes.Ldarg_0)); + list_inst_pars.Add(il.Create(OpCodes.Ldfld, flddef_module)); + foreach (var par in mtddef_target.Parameters) + { + if (par.Name.StartsWith("___")) + { + //___ means non public fields + string str_fldname = par.Name.Substring(3); + FieldDefinition flddef_target = module.ImportReference(itemActionType.GetField(str_fldname, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic)).Resolve(); + if (flddef_target == null) + throw new MissingFieldException($"Field with name \"{str_fldname}\" not found! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + if (flddef_target.IsStatic) + { + list_inst_pars.Add(il.Create((par.ParameterType.IsByReference) ? OpCodes.Ldsflda : OpCodes.Ldsfld, module.ImportReference(flddef_target))); + } + else + { + list_inst_pars.Add(il.Create(OpCodes.Ldarg_0)); + list_inst_pars.Add(il.Create(par.ParameterType.IsByReference ? OpCodes.Ldflda : OpCodes.Ldfld, module.ImportReference(flddef_target))); + } + } + else if (!MatchSpecialParameters(par, flddef_data, mtddef_target, mtdpinf_derived, typedef_newactiondata, list_inst_pars, il, module, isPostfix, dict_states, moduleID)) + { + //match param by name + int index = -1; + for (int j = 0; j < mtddef_root.Parameters.Count; j++) + { + if (mtddef_root.Parameters[j].Name == par.Name) + { + index = mtddef_root.Parameters[j].Index; + break; + } + } + if (index < 0) + throw new ArgumentException($"Parameter \"{par.Name}\" not found! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + try + { + //Log.Out($"Match Parameter {par.Name} to {mtddef_derived.Parameters[index].Name}/{mtddef_root.Parameters[index].Name} index: {index}"); + + } + catch (ArgumentOutOfRangeException e) + { + Log.Error($"index {index} parameter {par.Name}" + + $"root pars: {{{string.Join(",", mtddef_root.Parameters.Select(p => p.Name + "/" + p.Index).ToArray())}}}" + + $"derived pars: {{{string.Join(",", mtddef_derived.Parameters.Select(p => p.Name + "/" + p.Index).ToArray())}}}"); + throw e; + } + if (!mtddef_derived.Parameters[index].ParameterType.IsByReference) + { + list_inst_pars.Add(il.Create(par.ParameterType.IsByReference ? OpCodes.Ldarga_S : OpCodes.Ldarg_S, mtddef_derived.Parameters[index])); + } + else + { + list_inst_pars.Add(il.Create(OpCodes.Ldarg_S, mtddef_derived.Parameters[index])); + if (!par.ParameterType.IsByReference) + { + list_inst_pars.Add(il.Create(OpCodes.Ldind_Ref)); + } + } + } + } + return list_inst_pars; + } + + private static bool MatchSpecialParameters(ParameterDefinition par, FieldDefinition flddef_data, MethodDefinition mtddef_target, MethodPatchInfo mtdpinf_derived, TypeDefinition typedef_newactiondata, List list_inst_pars, ILProcessor il, ModuleDefinition module, bool isPostfix, Dictionary dict_states, string moduleID) + { + MethodDefinition mtddef_derived = mtdpinf_derived.Method; + switch (par.Name) + { + //load injected data instance + case "__customData": + if (flddef_data == null) + throw new ArgumentNullException($"No Injected ItemActionData in {mtddef_target.DeclaringType.FullName}!"); + int index = -1; + for (int j = 0; j < mtddef_derived.Parameters.Count; j++) + { + if (mtddef_derived.Parameters[j].ParameterType.Name == "ItemActionData") + { + index = j; + break; + } + } + if (index < 0) + throw new ArgumentException($"ItemActionData is not present in target method! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + list_inst_pars.Add(il.Create(OpCodes.Ldarg_S, mtddef_derived.Parameters[index])); + list_inst_pars.Add(il.Create(OpCodes.Castclass, typedef_newactiondata)); + list_inst_pars.Add(il.Create(par.ParameterType.IsByReference ? OpCodes.Ldflda : OpCodes.Ldfld, flddef_data)); + break; + //load ItemAction instance + case "__instance": + list_inst_pars.Add(il.Create(OpCodes.Ldarg_0)); + break; + //load return value + case "__result": + list_inst_pars.Add(il.Create(par.ParameterType.IsByReference ? OpCodes.Ldloca_S : OpCodes.Ldloc_S, mtddef_derived.Body.Variables[1])); + break; + //for postfix only, indicates whether original method is executed + case "__runOriginal": + if (par.ParameterType.IsByReference) + throw new ArgumentException($"__runOriginal is readonly! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + list_inst_pars.Add(il.Create(OpCodes.Ldloc_S, mtddef_derived.Body.Variables[0])); + break; + case "__state": + if (dict_states == null) + { + throw new ArgumentNullException($"__state is found in prefix but no matching postfix exists! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + } + if (!isPostfix && !dict_states.TryGetValue(moduleID, out var vardef)) + { + throw new KeyNotFoundException($"__state is found in prefix but not found in corresponding postfix! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + } + if (par.IsOut && isPostfix) + { + throw new ArgumentException($"__state is marked as out parameter in postfix! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + } + if (!par.IsOut && !isPostfix) + { + throw new ArgumentException($"__state is not marked as out in prefix! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + } + if (isPostfix) + { + vardef = new VariableDefinition(module.ImportReference(par.ParameterType)); + mtddef_derived.Body.Variables.Add(vardef); + dict_states.Add(moduleID, vardef); + var ins = mtddef_derived.Body.Instructions[0]; + il.InsertBefore(ins, il.Create(OpCodes.Ldloca_S, vardef)); + il.InsertBefore(ins, il.Create(OpCodes.Initobj, module.ImportReference(par.ParameterType))); + list_inst_pars.Add(il.Create(OpCodes.Ldloc_S, vardef)); + } + else + { + vardef = dict_states[moduleID]; + dict_states.Remove(moduleID); + list_inst_pars.Add(il.Create(OpCodes.Ldloca_S, vardef)); + } + break; + default: + return false; + } + return true; + } + + /// + /// Check if type is already generated in previous assemblies. + /// + /// Full type name. + /// The retrieved type, null if not found. + /// true if found. + private static bool TryFindType(string name, out Type type) + { + type = null; + foreach (var assembly in list_created) + { + type = assembly.GetType(name, false); + if (type != null) + return true; + } + return false; + } + + /// + /// Check if type is already generated in current working assembly definition. + /// + /// Full type name. + /// The retrieved type definition, null if not found. + /// true if found. + private static bool TryFindInCur(string name, out TypeDefinition typedef) + { + typedef = workingAssembly?.MainModule.GetType(name); + return typedef != null; + } + + public static string CreateFieldName(Type moduleType) + { + return (moduleType.FullName + "_" + moduleType.Assembly.GetName().Name).ReplaceInvalidChar(); + } + + public static string CreateFieldName(TypeReference moduleType) + { + return (moduleType.FullName + "_" + moduleType.Module.Assembly.Name.Name).ReplaceInvalidChar(); + } + + public static string CreateTypeName(Type itemActionType, params Type[] moduleTypes) + { + string typeName = itemActionType.FullName + "_" + itemActionType.Assembly.GetName().Name; + foreach (Type type in moduleTypes) + { + if (type != null) + typeName += "__" + type.FullName + "_" + type.Assembly.GetName().Name; + } + typeName = typeName.ReplaceInvalidChar(); + return typeName; + } + + public static string CreateTypeName(TypeReference itemActionType, params TypeReference[] moduleTypes) + { + string typeName = itemActionType.FullName + "_" + itemActionType.Module.Assembly.Name.Name; + foreach (TypeReference type in moduleTypes) + { + if (type != null) + typeName += "__" + type.FullName + "_" + type.Module.Assembly.Name.Name; + } + typeName = typeName.ReplaceInvalidChar(); + return typeName; + } + + private static string ReplaceInvalidChar(this string self) + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < self.Length; i++) + { + char c = self[i]; + if (!char.IsLetterOrDigit(c) && c != '_') + { + sb.Append('_'); + } + else + { + sb.Append(c); + } + } + return sb.ToString(); + } + } + + internal struct MethodOverrideInfo + { + public MethodInfo mtdinf_target; + public MethodInfo mtdinf_base; + public MethodReference mtdref_base; + public Type prefType; + + public MethodOverrideInfo(MethodInfo mtdinf_target, MethodInfo mtdinf_base, MethodReference mtddef_base, Type prefType) + { + this.mtdinf_target = mtdinf_target; + this.mtdinf_base = mtdinf_base; + this.mtdref_base = mtddef_base; + this.prefType = prefType; + } + } +} \ No newline at end of file diff --git a/Scripts/StaticManagers/LocalItemTagsManager.cs b/Scripts/StaticManagers/LocalItemTagsManager.cs new file mode 100644 index 0000000..ee7190c --- /dev/null +++ b/Scripts/StaticManagers/LocalItemTagsManager.cs @@ -0,0 +1,257 @@ +using KFCommonUtilityLib.Scripts.Utilities; +using System; +using System.Collections.Generic; +using UniLinq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace KFCommonUtilityLib.Scripts.StaticManagers +{ + /// + /// only used for item modifier tags. + /// + public static class LocalItemTagsManager + { + public static bool CanInstall(FastTags itemTags, ItemClassModifier modClass) + { + return modClass != null && (modClass.InstallableTags.IsEmpty || itemTags.Test_AnySet(modClass.InstallableTags)) && (modClass.DisallowedTags.IsEmpty || !itemTags.Test_AnySet(modClass.DisallowedTags)); + } + + public static bool CanStay(FastTags itemTags, ItemClassModifier modClass) + { + Log.Out($"mod class is null {modClass is null}"); + if (modClass != null) + { + Log.Out($"installable {modClass.InstallableTags.IsEmpty || itemTags.Test_AnySet(modClass.InstallableTags)}, disallowed {modClass.DisallowedTags.IsEmpty || !itemTags.Test_AnySet(modClass.DisallowedTags)}"); + } + return modClass == null || ((modClass.InstallableTags.IsEmpty || itemTags.Test_AnySet(modClass.InstallableTags)) && (modClass.DisallowedTags.IsEmpty || !itemTags.Test_AnySet(modClass.DisallowedTags))); + } + + public static bool CanInstallMod(this ItemValue itemValue, ItemClassModifier modToInstall) + { + if (modToInstall == null) + { + return false; + } + + FastTags tags_after_install = GetTagsAsIfInstalled(itemValue, modToInstall); + + if (itemValue.CosmeticMods != null) + { + foreach (var cosValue in itemValue.CosmeticMods) + { + if (cosValue == null || cosValue.IsEmpty()) + { + continue; + } + + ItemClassModifier cosClass = cosValue.ItemClass as ItemClassModifier; + if (cosClass == null) + { + continue; + } + + if (!tags_after_install.Test_AnySet(cosClass.InstallableTags) || tags_after_install.Test_AnySet(cosClass.DisallowedTags)) + { + return false; + } + } + } + + if (itemValue.Modifications != null) + { + foreach (var modValue in itemValue.Modifications) + { + if (modValue == null || modValue.IsEmpty()) + { + continue; + } + + ItemClassModifier modClass = modValue.ItemClass as ItemClassModifier; + if (modClass == null) + { + continue; + } + + if (!tags_after_install.Test_AnySet(modClass.InstallableTags) || tags_after_install.Test_AnySet(modClass.DisallowedTags)) + { + return false; + } + } + } + + return true; + } + + public static bool CanSwapMod(this ItemValue itemValue, ItemValue modToSwap, ItemClassModifier modToInstall) + { + if (modToInstall == null) + { + return false; + } + + FastTags tags_after_swap = GetTagsAsIfSwapped(itemValue, modToSwap, modToInstall); + + if (itemValue.CosmeticMods != null) + { + foreach (var cosValue in itemValue.CosmeticMods) + { + if (cosValue == null || cosValue.IsEmpty() || cosValue == modToSwap) + { + continue; + } + + ItemClassModifier cosClass = cosValue.ItemClass as ItemClassModifier; + if (cosClass == null) + { + continue; + } + + if (!tags_after_swap.Test_AnySet(cosClass.InstallableTags) || tags_after_swap.Test_AnySet(cosClass.DisallowedTags)) + { + return false; + } + } + } + + if (itemValue.Modifications != null) + { + foreach (var modValue in itemValue.Modifications) + { + if (modValue == null || modValue.IsEmpty() || modValue == modToSwap) + { + continue; + } + + ItemClassModifier modClass = modValue.ItemClass as ItemClassModifier; + if (modClass == null) + { + continue; + } + + if (!tags_after_swap.Test_AnySet(modClass.InstallableTags) || tags_after_swap.Test_AnySet(modClass.DisallowedTags)) + { + return false; + } + } + } + + return true; + } + + public static FastTags GetTags(ItemValue itemValue) + { + var str = string.Join(",", itemValue.GetPropertyOverrides("ItemTagsAppend")); + FastTags tagsToAdd = string.IsNullOrEmpty(str) ? FastTags.none : FastTags.Parse(str); + str = string.Join(",", itemValue.GetPropertyOverrides("ItemTagsRemove")); + FastTags tagsToRemove = string.IsNullOrEmpty(str) ? FastTags.none : FastTags.Parse(str); + return (itemValue.ItemClass.ItemTags | tagsToAdd).Remove(tagsToRemove); + } + + public static FastTags GetTagsAsIfNotInstalled(ItemValue itemValue, ItemValue modValue) + { + var str = string.Join(",", itemValue.GetPropertyOverridesWithoutMod(modValue, "ItemTagsAppend")); + FastTags tagsToAdd = string.IsNullOrEmpty(str) ? FastTags.none : FastTags.Parse(str); + str = string.Join(",", itemValue.GetPropertyOverridesWithoutMod(modValue, "ItemTagsRemove")); + FastTags tagsToRemove = string.IsNullOrEmpty(str) ? FastTags.none : FastTags.Parse(str); + return (itemValue.ItemClass.ItemTags | tagsToAdd).Remove(tagsToRemove); + } + + public static FastTags GetTagsAsIfInstalled(ItemValue itemValue, ItemClassModifier modClass) + { + string itemName = itemValue.ItemClass.GetItemName(); + string val = ""; + var str = string.Join(",", itemValue.GetPropertyOverrides("ItemTagsAppend")); + if (modClass.GetPropertyOverride("ItemTagsAppend", itemName, ref val)) + { + str = string.Join(",", str, val); + } + FastTags tagsToAdd = string.IsNullOrEmpty(str) ? FastTags.none : FastTags.Parse(str); + str = string.Join(",", itemValue.GetPropertyOverrides("ItemTagsRemove")); + if (modClass.GetPropertyOverride("ItemTagsRemove", itemName, ref val)) + { + str = string.Join(",", str, val); + } + FastTags tagsToRemove = string.IsNullOrEmpty(str) ? FastTags.none : FastTags.Parse(str); + return (itemValue.ItemClass.ItemTags | tagsToAdd).Remove(tagsToRemove); + } + + public static FastTags GetTagsAsIfSwapped(ItemValue itemValue, ItemValue modValue, ItemClassModifier modClass) + { + string itemName = itemValue.ItemClass.GetItemName(); + string val = ""; + var str = string.Join(",", itemValue.GetPropertyOverridesWithoutMod(modValue, "ItemTagsAppend")); + if (modClass.GetPropertyOverride("ItemTagsAppend", itemName, ref val)) + { + str = string.Join(",", str, val); + } + FastTags tagsToAdd = string.IsNullOrEmpty(str) ? FastTags.none : FastTags.Parse(str); + str = string.Join(",", itemValue.GetPropertyOverridesWithoutMod(modValue, "ItemTagsRemove")); + if (modClass.GetPropertyOverride("ItemTagsRemove", itemName, ref val)) + { + str = string.Join(",", str, val); + } + FastTags tagsToRemove = string.IsNullOrEmpty(str) ? FastTags.none : FastTags.Parse(str); + return (itemValue.ItemClass.ItemTags | tagsToAdd).Remove(tagsToRemove); + } + + public static IEnumerable GetPropertyOverrides(this ItemValue self, string _propertyName) + { + if (self == null || (self.Modifications.Length == 0 && self.CosmeticMods.Length == 0)) + { + yield break; + } + + string _value = ""; + string itemName = self.ItemClass.GetItemName(); + for (int i = 0; i < self.Modifications.Length; i++) + { + ItemValue itemValue = self.Modifications[i]; + if (itemValue != null && itemValue.ItemClass is ItemClassModifier itemClassModifier && itemClassModifier.GetPropertyOverride(_propertyName, itemName, ref _value)) + { + yield return _value; + } + } + + _value = ""; + for (int j = 0; j < self.CosmeticMods.Length; j++) + { + ItemValue itemValue2 = self.CosmeticMods[j]; + if (itemValue2 != null && itemValue2.ItemClass is ItemClassModifier itemClassModifier2 && itemClassModifier2.GetPropertyOverride(_propertyName, itemName, ref _value)) + { + yield return _value; + } + } + } + + public static IEnumerable GetPropertyOverridesWithoutMod(this ItemValue self, ItemValue mod, string _propertyName) + { + if (self == null || (self.Modifications.Length == 0 && self.CosmeticMods.Length == 0)) + { + yield break; + } + + string _value = ""; + string itemName = self.ItemClass.GetItemName(); + for (int i = 0; i < self.Modifications.Length; i++) + { + ItemValue itemValue = self.Modifications[i]; + if (itemValue != null && itemValue != mod && itemValue.ItemClass is ItemClassModifier itemClassModifier && itemClassModifier.GetPropertyOverride(_propertyName, itemName, ref _value)) + { + yield return _value; + } + } + + _value = ""; + for (int j = 0; j < self.CosmeticMods.Length; j++) + { + ItemValue itemValue2 = self.CosmeticMods[j]; + if (itemValue2 != null && itemValue2 != mod && itemValue2.ItemClass is ItemClassModifier itemClassModifier2 && itemClassModifier2.GetPropertyOverride(_propertyName, itemName, ref _value)) + { + yield return _value; + } + } + } + } +} diff --git a/Scripts/StaticManagers/MultiActionManager.cs b/Scripts/StaticManagers/MultiActionManager.cs new file mode 100644 index 0000000..79ffde7 --- /dev/null +++ b/Scripts/StaticManagers/MultiActionManager.cs @@ -0,0 +1,600 @@ +using KFCommonUtilityLib.Scripts.ConsoleCmd; +using KFCommonUtilityLib.Scripts.Utilities; +using System; +using System.Collections.Generic; +using UniLinq; +using UnityEngine; + +namespace KFCommonUtilityLib.Scripts.StaticManagers +{ + //concept: maintain an entityID-AltActionIndice mapping on both server and client + //and get the correct action before calling ItemAction.* + //always set MinEventParams.itemActionData + //done: set meta and ammoindex on switching mode, keep current mode in metadata + //should take care of accuracy updating + //partially done: should support shared meta + //alt actions should be considered primary, redirect index == 0 to custom method + //redirect ItemClass.Actions[0] to custom method + //however, player input handling is redirected to action0 so that alternative module can dispatch it to correct action. + //patch GameManager.updateSendClientPlayerPositionToServer to sync data, so that mode change always happens after holding item change + + public struct MultiActionIndice + { + public const int MAX_ACTION_COUNT = 3; + public unsafe fixed sbyte indices[MAX_ACTION_COUNT]; + public unsafe fixed sbyte metaIndice[MAX_ACTION_COUNT]; + public readonly byte modeCount; + + public unsafe MultiActionIndice(ItemClass item) + { + ItemAction[] actions = item.Actions; + indices[0] = 0; + metaIndice[0] = 0; + byte last = 1; + for (sbyte i = 3; i < actions.Length && last < MAX_ACTION_COUNT; i++) + { + if (actions[i] != null) + { + indices[last] = i; + if (actions[i].Properties.Values.TryGetValue("ShareMetaWith", out string str) && sbyte.TryParse(str, out sbyte shareWith)) + { + metaIndice[last] = shareWith; + } + else + { + metaIndice[last] = i; + } + last++; + } + } + modeCount = last; + for (; last < MAX_ACTION_COUNT; last++) + { + indices[last] = -1; + metaIndice[last] = -1; + } + } + + public unsafe int GetActionIndexForMode(int mode) + { + return indices[mode]; + } + + public unsafe int GetMetaIndexForMode(int mode) + { + return metaIndice[mode]; + } + + public unsafe int GetMetaIndexForActionIndex(int actionIndex) + { + return metaIndice[GetModeForAction(actionIndex)]; + } + + public int GetModeForAction(int actionIndex) + { + int mode = -1; + for (int i = 0; i < MultiActionIndice.MAX_ACTION_COUNT; i++) + { + unsafe + { + if (indices[i] == actionIndex) + { + mode = i; + break; + } + } + } + return mode; + } + } + + //MultiActionMapping instance should be changed on ItemAction.StartHolding, so we only need to send curIndex. + public class MultiActionMapping + { + public const string STR_MULTI_ACTION_INDEX = "MultiActionIndex"; + public readonly MultiActionIndice indices; + private int slotIndex; + private int curIndex; + private int lastDisplayMode = -1; + private readonly bool[] unlocked; + private ActionModuleAlternative.AlternativeData altData; + public EntityAlive entity; + public string toggleSound; + + public ItemValue ItemValue + { + get + { + var res = entity.inventory.GetItem(slotIndex).itemValue; + if (res.IsEmpty()) + { + return null; + } + return res; + } + } + + public int SlotIndex => slotIndex; + + /// + /// when set CurIndex from local input, also set manager to dirty to update the index on other clients + /// + public int CurMode + { + get => curIndex; + set + { + unsafe + { + if (value < 0) + value = 0; + else + { + while (value < MultiActionIndice.MAX_ACTION_COUNT) + { + if (unlocked[value]) + break; + value++; + } + //mostly for CurIndex++, cycle through available indices + if (value >= MultiActionIndice.MAX_ACTION_COUNT || indices.indices[value] == -1) + value = 0; + } + if (curIndex == value) + return; + + SaveMeta(); + + //load current meta and ammo index from metadata + curIndex = value; + ReadMeta(); + entity.emodel?.avatarController?.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, CurActionIndex, false); + //altData.OverrideMuzzleTransform(curIndex); + } + } + } + + //for ItemClass.Actions access + public int CurActionIndex => indices.GetActionIndexForMode(curIndex); + + //for meta saving on mode switch only? + public int CurMetaIndex => indices.GetMetaIndexForMode(curIndex); + + public int ModeCount => indices.modeCount; + + //mapping object is created on StartHolding + //we set the curIndex field instead of the property, according to following situations: + //1. it's a newly created ItemValue, meta and ammo index belongs to action0, no saving is needed; + //2. it's an existing ItemValue, meta and ammo index is set to its action index, still saving is unnecessary. + internal MultiActionMapping(ActionModuleAlternative.AlternativeData altData, MultiActionIndice indices, EntityAlive entity, ItemValue itemValueTemp, string toggleSound, int slotIndex, bool[] unlocked) + { + this.altData = altData; + this.indices = indices; + this.entity = entity; + this.slotIndex = slotIndex; + this.unlocked = unlocked; + object res = itemValueTemp.GetMetadata(STR_MULTI_ACTION_INDEX); + if (res is false || res is null) + { + itemValueTemp.SetMetadata(STR_MULTI_ACTION_INDEX, 0, TypedMetadataValue.TypeTag.Integer); + curIndex = 0; + } + else + { + curIndex = (int)res; + ReadMeta(); + } + + unsafe + { + for (int i = 0; i < MultiActionIndice.MAX_ACTION_COUNT; i++) + { + int metaIndex = indices.metaIndice[i]; + if (metaIndex < 0) + break; + if (!itemValueTemp.HasMetadata(MultiActionUtils.ActionMetaNames[metaIndex])) + { + itemValueTemp.SetMetadata(MultiActionUtils.ActionMetaNames[metaIndex], 0, TypedMetadataValue.TypeTag.Integer); + } +#if DEBUG + else + { + Log.Out($"{MultiActionUtils.ActionMetaNames[metaIndex]}: {itemValueTemp.GetMetadata(MultiActionUtils.ActionMetaNames[metaIndex]).ToString()}"); + } +#endif + if (!itemValueTemp.HasMetadata(MultiActionUtils.ActionSelectedAmmoNames[metaIndex])) + { + itemValueTemp.SetMetadata(MultiActionUtils.ActionSelectedAmmoNames[metaIndex], 0, TypedMetadataValue.TypeTag.Integer); + } +#if DEBUG + else + { + Log.Out($"{MultiActionUtils.ActionSelectedAmmoNames[metaIndex]}: {itemValueTemp.GetMetadata(MultiActionUtils.ActionSelectedAmmoNames[metaIndex]).ToString()}"); + } +#endif + } + } + this.toggleSound = toggleSound; + entity.emodel?.avatarController?.UpdateInt(MultiActionUtils.ExecutingActionIndexHash, CurActionIndex, false); +#if DEBUG + Log.Out($"MultiAction mode {curIndex}, meta {itemValueTemp.Meta}, ammo index {itemValueTemp.SelectedAmmoTypeIndex}\n {StackTraceUtility.ExtractStackTrace()}"); +#endif + } + + public void SaveMeta(ItemValue _itemValue = null) + { + //save previous meta and ammo index to metadata + int curMetaIndex = CurMetaIndex; + ItemValue itemValue = _itemValue ?? ItemValue; + if (itemValue == null) + return; + ItemAction[] actions = itemValue.ItemClass.Actions; + if (CurActionIndex < 0 || CurActionIndex >= actions.Length) + return; + ItemActionAttack itemActionAttack = actions[CurActionIndex] as ItemActionAttack; + if (itemActionAttack == null) + return; + if (ConsoleCmdReloadLog.LogInfo) + { + Log.Out($"Saving meta for item {itemValue.ItemClass.Name}"); + } + itemValue.SetMetadata(MultiActionUtils.ActionMetaNames[curMetaIndex], itemValue.Meta, TypedMetadataValue.TypeTag.Integer); + itemValue.SetMetadata(MultiActionUtils.ActionSelectedAmmoNames[curMetaIndex], (int)itemValue.SelectedAmmoTypeIndex, TypedMetadataValue.TypeTag.Integer); + if (itemValue.SelectedAmmoTypeIndex > itemActionAttack.MagazineItemNames.Length) + { + Log.Error($"SAVING META ERROR: AMMO INDEX LARGER THAN AMMO ITEM COUNT!\n{StackTraceUtility.ExtractStackTrace()}"); + } + if (ConsoleCmdReloadLog.LogInfo) + { + ConsoleCmdMultiActionItemValueDebug.LogMeta(itemValue); + Log.Out($"Save Meta stacktrace:\n{StackTraceUtility.ExtractStackTrace()}"); + } + } + + public void ReadMeta(ItemValue _itemValue = null) + { + int curMetaIndex = CurMetaIndex; + ItemValue itemValue = _itemValue ?? ItemValue; + if (itemValue == null) + return; + itemValue.SetMetadata(STR_MULTI_ACTION_INDEX, curIndex, TypedMetadataValue.TypeTag.Integer); + object res = itemValue.GetMetadata(MultiActionUtils.ActionMetaNames[curMetaIndex]); + if (res is false || res is null) + { + itemValue.SetMetadata(MultiActionUtils.ActionMetaNames[curMetaIndex], 0, TypedMetadataValue.TypeTag.Integer); + itemValue.Meta = 0; + } + else + { + itemValue.Meta = (int)res; + } + res = itemValue.GetMetadata(MultiActionUtils.ActionSelectedAmmoNames[curMetaIndex]); + if (res is false || res is null) + { + itemValue.SetMetadata(MultiActionUtils.ActionSelectedAmmoNames[curMetaIndex], 0, TypedMetadataValue.TypeTag.Integer); + itemValue.SelectedAmmoTypeIndex = 0; + } + else + { + itemValue.SelectedAmmoTypeIndex = (byte)(int)res; + } + if (ConsoleCmdReloadLog.LogInfo) + { + ConsoleCmdMultiActionItemValueDebug.LogMeta(itemValue); + Log.Out($"Read Meta stacktrace:\n{StackTraceUtility.ExtractStackTrace()}"); + } + } + + public int SetupRadial(XUiC_Radial _xuiRadialWindow, EntityPlayerLocal _epl) + { + _xuiRadialWindow.ResetRadialEntries(); + int preSelectedIndex = -1; + string[] magazineItemNames = ((ItemActionAttack)_epl.inventory.holdingItem.Actions[CurActionIndex]).MagazineItemNames; + bool[] disableStates = CommonUtilityPatch.GetUnusableItemEntries(magazineItemNames, _epl, CurActionIndex); + for (int i = 0; i < magazineItemNames.Length; i++) + { + ItemClass ammoClass = ItemClass.GetItemClass(magazineItemNames[i], false); + if (ammoClass != null && (!_epl.isHeadUnderwater || ammoClass.UsableUnderwater) && !disableStates[i]) + { + int ammoCount = _xuiRadialWindow.xui.PlayerInventory.GetItemCount(ammoClass.Id); + bool isCurrentUsing = _epl.inventory.holdingItemItemValue.SelectedAmmoTypeIndex == i; + _xuiRadialWindow.CreateRadialEntry(i, ammoClass.GetIconName(), (ammoCount > 0) ? "ItemIconAtlas" : "ItemIconAtlasGreyscale", ammoCount.ToString(), ammoClass.GetLocalizedItemName(), isCurrentUsing); + if (isCurrentUsing) + { + preSelectedIndex = i; + } + } + } + + return preSelectedIndex; + } + + public bool CheckDisplayMode() + { + if (lastDisplayMode == CurMode) + { + return false; + } + else + { + lastDisplayMode = CurMode; + return true; + } + } + + public bool IsActionUnlocked(int actionIndex) + { + if (actionIndex >= MultiActionIndice.MAX_ACTION_COUNT || actionIndex < 0) + return false; + return unlocked[actionIndex]; + } + } + + public static class MultiActionManager + { + //clear on game load + private static readonly Dictionary dict_mappings = new Dictionary(); + private static readonly Dictionary dict_indice = new Dictionary(); + private static readonly Dictionary[]> dict_item_action_exclude_tags = new Dictionary[]>(); + private static readonly Dictionary dict_item_action_exclude_mod_property = new Dictionary(); + private static readonly Dictionary dict_item_action_exclude_mod_passive = new Dictionary(); + private static readonly Dictionary dict_item_action_exclude_mod_trigger = new Dictionary(); + + //should set to true when: + //mode switch input received; + //start holding new multi action weapon.? + //if true, send local curIndex to other clients in updateSendClientPlayerPositionToServer. + public static bool LocalModeChanged { get; set; } + + public static void PostloadCleanup() + { + dict_mappings.Clear(); + dict_indice.Clear(); + } + + public static void PreloadCleanup() + { + dict_item_action_exclude_tags.Clear(); + dict_item_action_exclude_mod_property.Clear(); + dict_item_action_exclude_mod_passive.Clear(); + dict_item_action_exclude_mod_trigger.Clear(); + } + + public static void ParseItemActionExcludeTagsAndModifiers(ItemClass item) + { + if (item == null) + return; + FastTags[] tags = null; + int[][] properties = null, passives = null, triggers = null; + for (int i = 0; i < item.Actions.Length; i++) + { + if (item.Actions[i] != null) + { + if (item.Actions[i].Properties.Values.TryGetValue("ExcludeTags", out string str)) + { + if (tags == null) + { + tags = new FastTags[ItemClass.cMaxActionNames]; + dict_item_action_exclude_tags.Add(item.Id, tags); + } + tags[i] = FastTags.Parse(str); + } + if (item.Actions[i].Properties.Values.TryGetValue("ExcludeMods", out str)) + { + if (properties == null) + { + properties = new int[ItemClass.cMaxActionNames][]; + dict_item_action_exclude_mod_property.Add(item.Id, properties); + } + properties[i] = str.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) + .Where(s => !string.IsNullOrEmpty(s)) + .Select(s => ItemClass.GetItemClass(s, false)) + .Where(_item => _item != null) + .Select(_item => _item.Id) + .ToArray(); + //Log.Out($"EXCLUDE PROPERTIES FROM ITEM {item.Name} ITEMID {item.Id} ACTION {i} : {string.Join(" ", properties[i])}"); + } + if (item.Actions[i].Properties.Values.TryGetValue("ExcludePassives", out str)) + { + if (passives == null) + { + passives = new int[ItemClass.cMaxActionNames][]; + dict_item_action_exclude_mod_passive.Add(item.Id, passives); + } + passives[i] = str.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) + .Where(s => !string.IsNullOrEmpty(s)) + .Select(s => ItemClass.GetItemClass(s, false)) + .Where(_item => _item != null) + .Select(_item => _item.Id) + .ToArray(); + //Log.Out($"EXCLUDE PASSIVES FROM ITEM {item.Name} ITEMID {item.Id} ACTION {i} : {string.Join(" ", passives[i])}"); + } + if (item.Actions[i].Properties.Values.TryGetValue("ExcludeTriggers", out str)) + { + if (triggers == null) + { + triggers = new int[ItemClass.cMaxActionNames][]; + dict_item_action_exclude_mod_trigger.Add(item.Id, triggers); + } + triggers[i] = str.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) + .Where(s => !string.IsNullOrEmpty(s)) + .Select(s => ItemClass.GetItemClass(s, false)) + .Where(_item => _item != null) + .Select(_item => _item.Id) + .ToArray(); + //Log.Out($"EXCLUDE TRIGGERS FROM ITEM {item.Name} ITEMID {item.Id} ACTION {i} : {string.Join(" ", triggers[i])}"); + } + } + } + } + + public static void ModifyItemTags(ItemValue itemValue, ItemActionData actionData, ref FastTags tags) + { + if (itemValue == null || actionData == null || !dict_item_action_exclude_tags.TryGetValue(itemValue.type, out var arr_tags)) + { + return; + } + + tags = tags.Remove(arr_tags[actionData.indexInEntityOfAction]); + } + + public static bool ShouldExcludeProperty(int itemId, int modId, int actionIndex) + { + return dict_item_action_exclude_mod_property.TryGetValue(itemId, out var arr_exclude) && arr_exclude[actionIndex] != null && Array.IndexOf(arr_exclude[actionIndex], modId) >= 0; + } + + public static bool ShouldExcludePassive(int itemId, int modId, int actionIndex) + { + return dict_item_action_exclude_mod_passive.TryGetValue(itemId, out var arr_exclude) && arr_exclude[actionIndex] != null && Array.IndexOf(arr_exclude[actionIndex], modId) >= 0; + } + + public static bool ShouldExcludeTrigger(int itemId, int modId, int actionIndex) + { + return dict_item_action_exclude_mod_trigger.TryGetValue(itemId, out var arr_exclude) && arr_exclude[actionIndex] != null && Array.IndexOf(arr_exclude[actionIndex], modId) >= 0; + } + + public static void UpdateLocalMetaSave(int playerID) + { + if (dict_mappings.TryGetValue(playerID, out MultiActionMapping mapping)) + { + mapping?.SaveMeta(); + } + } + + public static MultiActionIndice GetActionIndiceForItemID(int itemID) + { + if (dict_indice.TryGetValue(itemID, out MultiActionIndice indice)) + return indice; + ItemClass item = ItemClass.GetForId(itemID); + if (item == null) + return indice; + indice = new MultiActionIndice(item); + dict_indice[itemID] = indice; + return indice; + } + + public static void ToggleLocalActionIndex(EntityPlayerLocal player) + { + if (player == null || !dict_mappings.TryGetValue(player.entityId, out MultiActionMapping mapping)) + return; + + if (mapping.ModeCount <= 1 || player.inventory.IsHoldingItemActionRunning()) + return; + int prevMode = mapping.CurMode; + mapping.CurMode++; + if (prevMode != mapping.CurMode) + { + FireToggleModeEvent(player, mapping); + player.inventory.CallOnToolbeltChangedInternal(); + } + } + + public static void FireToggleModeEvent(EntityPlayerLocal player, MultiActionMapping mapping) + { + player.PlayOneShot(mapping.toggleSound); + LocalModeChanged = true; + player.MinEventContext.ItemActionData = player.inventory.holdingItemData.actionData[mapping.CurActionIndex]; + player.FireEvent(CustomEnums.onSelfItemSwitchMode); + } + + public static void SetMappingForEntity(int entityID, MultiActionMapping mapping) + { + dict_mappings[entityID] = mapping; + //Log.Out($"current item index mapping: {((mapping == null || mapping.itemValue == null) ? "null" : mapping.itemValue.ItemClass.Name)}"); + } + + public static bool SetModeForEntity(int entityID, int mode) + { + if (dict_mappings.TryGetValue(entityID, out MultiActionMapping mapping) && mapping != null) + { + int prevMode = mapping.CurMode; + mapping.CurMode = mode; + return prevMode != mapping.CurMode; + } + return false; + } + + public static int GetModeForEntity(int entityID) + { + if (!dict_mappings.TryGetValue(entityID, out MultiActionMapping mapping) || mapping == null) + return 0; + return mapping.CurMode; + } + + public static int GetActionIndexForEntity(EntityAlive entity) + { + if (entity == null || !dict_mappings.TryGetValue(entity.entityId, out var mapping) || mapping == null) + return 0; + return mapping.CurActionIndex; + } + + public static int GetMetaIndexForEntity(int entityID) + { + if (!dict_mappings.TryGetValue(entityID, out var mapping) || mapping == null) + return 0; + return mapping.CurMetaIndex; + } + + public static int GetMetaIndexForActionIndex(int entityID, int actionIndex) + { + if (!dict_mappings.TryGetValue(entityID, out var mapping) || mapping == null) + { + return actionIndex; + } + + int mode = mapping.indices.GetModeForAction(actionIndex); + if (mode > 0) + { + unsafe + { + return mapping.indices.metaIndice[mode]; + } + } + return actionIndex; + } + + public static MultiActionMapping GetMappingForEntity(int entityID) + { + dict_mappings.TryGetValue(entityID, out var mapping); + return mapping; + } + + internal static float inputCD = 0; + internal static void UpdateLocalInput(EntityPlayerLocal player, PlayerActionsLocal localActions, bool isUIOpen, float _dt) + { + if (inputCD > 0) + { + inputCD = Math.Max(0, inputCD - _dt); + } + if (isUIOpen || inputCD > 0 || player.emodel.IsRagdollActive || player.IsDead() || player.AttachedToEntity != null) + { + return; + } + + if (PlayerActionKFLib.Instance.ToggleActionMode && PlayerActionKFLib.Instance.ToggleActionMode.WasPressed) + { + var mapping = GetMappingForEntity(player.entityId); + + if (mapping == null) + { + return; + } + + if (player.inventory.IsHoldingItemActionRunning()) + { + return; + } + + if (localActions.Reload.WasPressed || localActions.PermanentActions.Reload.WasPressed) + { + inputCD = 0.1f; + return; + } + + player.inventory.Execute(mapping.CurActionIndex, true, localActions); + localActions.Primary.ClearInputState(); + ToggleLocalActionIndex(player); + } + } + } +} diff --git a/Scripts/StaticManagers/RecoilManager.cs b/Scripts/StaticManagers/RecoilManager.cs new file mode 100644 index 0000000..2b30a1c --- /dev/null +++ b/Scripts/StaticManagers/RecoilManager.cs @@ -0,0 +1,370 @@ +using CameraShake; +using GearsAPI.Settings.Global; +using UnityEngine; + +namespace KFCommonUtilityLib.Scripts.StaticManagers +{ + public static class RecoilManager + { + private enum RecoilState + { + None, + Recoil, + Return + } + + private static RecoilState state; + private static float lastKickTime = 0f; + //private static float recoilScaledDelta = 0f; + //private static float returnScaledDelta = 0f; + private static Vector2 targetRotationXY = Vector2.zero; + private static Vector2 targetReturnXY = Vector2.zero; + private static Vector3 returnSpeedCur = Vector3.zero; + private static Vector2 totalRotationXY = Vector2.zero; + private static Vector3 totalReturnCur = Vector3.zero; + private static EntityPlayerLocal player; + //Gears options + private static bool enableCap = false; + private static bool enableDynamicCap = false; + private static bool enableSoftCap = false; + private static bool enablePreRecoilCompensation = false; + private static float maxRecoilAngle = 15; + private static int maxDynamicRecoilCapShots = 6; + private static float recoilCapRemain = 1f; + private static float recoilCompensationSensitivityMultiplier = 0f; + private const float DEFAULT_SNAPPINESS_PISTOL = 6f; + private const float DEFAULT_SNAPPINESS_RIFLE = 3.6f; + private const float DEFAULT_SNAPPINESS_SHOTGUN = 6f; + private const float DEFAULT_RETURN_SPEED_PISTOL = 8f; + private const float DEFAULT_RETURN_SPEED_RIFLE = 4f; + private const float DEFAULT_RETURN_SPEED_SHOTGUN = 4f; + private static readonly FastTags PistolTag = FastTags.Parse("pistol"); + private static readonly FastTags ShotgunTag = FastTags.Parse("shotgun"); + + private static void ClearData() + { + state = RecoilState.None; + //recoilScaledDelta = 0; + returnSpeedCur = Vector3.zero; + targetRotationXY = Vector2.zero; + targetReturnXY = Vector2.zero; + totalRotationXY = Vector2.zero; + totalReturnCur = Vector3.zero; + lastKickTime = 0f; + } + + public static void InitRecoilSettings(IModGlobalSettings settings) + { + var capSetting = settings.GetTab("RecoilSettings").GetCategory("Capping"); + + var recoilCompensationSetting = capSetting.GetSetting("RecoilCompensationSensitivityMultiplier") as ISliderGlobalSetting; + recoilCompensationSensitivityMultiplier = float.Parse(recoilCompensationSetting.CurrentValue); + recoilCompensationSetting.OnSettingChanged += (setting, newValue) => recoilCompensationSensitivityMultiplier = float.Parse(newValue); + + var preRecoilCompensationSetting = capSetting.GetSetting("EnablePreRecoilCompensation") as ISwitchGlobalSetting; + enablePreRecoilCompensation = preRecoilCompensationSetting.CurrentValue == "Enable"; + preRecoilCompensationSetting.OnSettingChanged += (setting, newValue) => enablePreRecoilCompensation = newValue == "Enable"; + + var enableCapSetting = capSetting.GetSetting("EnableCap") as ISwitchGlobalSetting; + enableCap = enableCapSetting.CurrentValue == "Enable"; + enableCapSetting.OnSettingChanged += (setting, newValue) => + { + enableCap = newValue == "Enable"; + UpdateSettingState(setting.Category); + }; + + var recoilRemainSetting = capSetting.GetSetting("RecoilRemain") as ISliderGlobalSetting; + recoilCapRemain = float.Parse(recoilRemainSetting.CurrentValue); + recoilRemainSetting.OnSettingChanged += (setting, newValue) => recoilCapRemain = float.Parse(newValue); + + var enableSoftCapSetting = capSetting.GetSetting("EnableSoftCap") as ISwitchGlobalSetting; + enableSoftCap = enableSoftCapSetting.CurrentValue == "Enable"; + enableSoftCapSetting.OnSettingChanged += (setting, newValue) => enableSoftCap = newValue == "Enable"; + + var maxRecoilAngleSetting = capSetting.GetSetting("MaxRecoilAngle") as ISliderGlobalSetting; + maxRecoilAngle = float.Parse(maxRecoilAngleSetting.CurrentValue); + maxRecoilAngleSetting.OnSettingChanged += (setting, newValue) => maxRecoilAngle = float.Parse(newValue); + + var enableDynamicCapSetting = capSetting.GetSetting("EnableDynamicCap") as ISwitchGlobalSetting; + enableDynamicCap = enableDynamicCapSetting.CurrentValue == "Enable"; + enableDynamicCapSetting.OnSettingChanged += (setting, newValue) => + { + enableDynamicCap = newValue == "Enable"; + UpdateSettingState(setting.Category); + }; + + var maxDynamicRecoilCapShotsSetting = capSetting.GetSetting("MaxDynamicRecoilCapShots") as ISliderGlobalSetting; + maxDynamicRecoilCapShots = int.Parse(maxDynamicRecoilCapShotsSetting.CurrentValue); + maxDynamicRecoilCapShotsSetting.OnSettingChanged += (setting, newValue) => maxDynamicRecoilCapShots = int.Parse(newValue); + UpdateSettingState(capSetting); + } + + private static void UpdateSettingState(IGlobalModSettingsCategory category) + { + category.GetSetting("EnableCap").Enabled = true; + category.GetSetting("RecoilRemain").Enabled = enableCap; + category.GetSetting("EnableSoftCap").Enabled = enableCap; + category.GetSetting("MaxRecoilAngle").Enabled = enableCap && !enableDynamicCap; + category.GetSetting("EnableDynamicCap").Enabled = enableCap; + category.GetSetting("MaxDynamicRecoilCapShots").Enabled = enableCap && enableDynamicCap; + } + + public static void InitPlayer(EntityPlayerLocal _player) + { + ClearData(); + player = _player; + player.cameraTransform.AddMissingComponent(); + } + + public static void Cleanup() + { + ClearData(); + player = null; + } + + private static float shakeFreq = 20; + private static int shakeBounce = 5; + public static void AddRecoil(Vector2 recoilRangeHor, Vector2 recoilRangeVer) + { + if (player == null) { return; } + state = RecoilState.Recoil; + //recoilScaledDelta = 0; + returnSpeedCur = Vector3.zero; + //returnScaledDelta = 0; + float cap = 0f; + if (enableCap) + { + if (enableDynamicCap) + { + cap = Mathf.Abs(recoilRangeVer.y) * maxDynamicRecoilCapShots; + } + else + { + cap = maxRecoilAngle; + } + } + float cameraShakeStrength = EffectManager.GetValue(CustomEnums.RecoilCameraShakeStrength, player.inventory.holdingItemItemValue, 0.12f, player); + float targetRotationX = player.rand.RandomRange(recoilRangeVer.x, recoilRangeVer.y); + float targetRotationY = player.rand.RandomRange(recoilRangeHor.x, recoilRangeHor.y); + if (enableCap) + { + if (Mathf.Abs(totalRotationXY.x) >= Mathf.Abs(cap)) + { + targetRotationX *= recoilCapRemain; + } + else if (enableSoftCap) + { + targetRotationX *= Mathf.Lerp(recoilCapRemain, 1f, 1 - Mathf.InverseLerp(0, Mathf.Abs(cap), Mathf.Abs(totalRotationXY.x))); + //targetRotationX *= Mathf.Lerp(recoilCapRemain, 1f, Mathf.Cos(Mathf.PI * .5f * Mathf.InverseLerp(0, Mathf.Abs(cap), Mathf.Abs(totalRotationXY.x)))); + } + } + if (!player.AimingGun) + { + targetRotationXY += new Vector2(targetRotationX, targetRotationY) * 2f; + totalRotationXY += new Vector2(targetRotationX, targetRotationY) * 2f; + CameraShaker.Presets.ShortShake3D(cameraShakeStrength * 1.2f, shakeFreq, shakeBounce); + } + else + { + targetRotationXY += new Vector2(targetRotationX, targetRotationY); + totalRotationXY += new Vector2(targetRotationX, targetRotationY); + CameraShaker.Presets.ShortShake3D(cameraShakeStrength, shakeFreq, shakeBounce); + } + lastKickTime = Time.time; + //if (enableCap) + //{ + // float totalRotationXCapped = Mathf.Clamp(totalRotationXY.x, -cap, cap); + // targetRotationXY.x = Mathf.Clamp(targetRotationXY.x + totalRotationXCapped - totalRotationXY.x, -cap, cap); + // totalRotationXY.x = totalRotationXCapped; + //} + } + + public static float CompensateX(float movedX) + { + if (!enablePreRecoilCompensation) + { + if (targetReturnXY.x * movedX < 0) + targetReturnXY.x = Mathf.Max(0, targetReturnXY.x + movedX); + return movedX; + } + float targetX = targetRotationXY.x; + float returnX = targetReturnXY.x; + float res = Compensate(movedX, player.movementInput.rotation.x, ref targetX, ref returnX); + targetRotationXY.x = targetX; + targetReturnXY.x = returnX; + return res; + } + + public static float CompensateY(float movedY) + { + if (!enablePreRecoilCompensation) + { + if (targetReturnXY.y * movedY < 0) + targetReturnXY.y = Mathf.Max(0, targetReturnXY.y + movedY); + return movedY; + } + float targetY = targetRotationXY.y; + float returnY = targetReturnXY.y; + float res = Compensate(movedY, player.movementInput.rotation.y, ref targetY, ref returnY); + targetRotationXY.y = targetY; + targetReturnXY.y = returnY; + return res; + } + + private static float Compensate(float moved, float original, ref float targetRotation, ref float targetReturn) + { + float dsScale = 1; + if (player.AimingGun) + { + dsScale = Mathf.Lerp(1, 1 / PlayerMoveController.Instance.mouseZoomSensitivity, recoilCompensationSensitivityMultiplier); + //dsScale = 1 / GamePrefs.GetFloat(EnumGamePrefs.OptionsZoomSensitivity); + //if (player.inventory.holdingItemData.actionData[1] is IModuleContainerFor dsDataContainer && dsDataContainer.Instance.activated) + //{ + // dsScale *= Mathf.Sqrt(dsDataContainer.Instance.ZoomRatio); + //} + } + float modified = moved * dsScale - original; + float target = ApplyOppositeCompensation(targetRotation, modified, out modified); + modified /= dsScale; + float compensated = target - targetRotation; + //if (compensated < 0) + //{ + // Log.Out($"compensated {compensated} prev {targetRotation} cur {target}"); + //} + targetRotation = target; + float @return = targetReturn + (modified * targetReturn < 0 ? modified : 0); + //Log.Out($"return {@return} targetReturn {targetReturn} compensated {compensated} modified {modified}"); + if (@return * targetReturn > 0) + { + targetReturn = @return; + } + else + { + targetReturn = 0; + } + return original + modified; + } + + public static void ApplyRecoil() + { + if (player == null) + return; + if (state == RecoilState.Recoil) + { + //Log.Out($"target rotation {targetRotationXY}"); + //if (targetRotationXY.sqrMagnitude <= 1e-6) + //{ + // targetRotationXY = Vector3.zero; + // recoilScaledDelta = 1; + // returnSpeedCur = Vector3.zero; + // state = RecoilState.Return; + // return; + //} + //returnScaledDelta = 0; + + FastTags actionTags = player.inventory.holdingItemItemValue.ItemClass.ItemTags; + MultiActionManager.ModifyItemTags(player.inventory.holdingItemItemValue, player.inventory.holdingItemData.actionData[MultiActionManager.GetActionIndexForEntity(player)], ref actionTags); + float snappinessDefault; + if (actionTags.Test_AnySet(PistolTag)) + { + snappinessDefault = DEFAULT_SNAPPINESS_PISTOL; + } + else if (actionTags.Test_AnySet(ShotgunTag)) + { + snappinessDefault = DEFAULT_SNAPPINESS_SHOTGUN; + } + else + { + snappinessDefault = DEFAULT_SNAPPINESS_RIFLE; + } + float snappiness = EffectManager.GetValue(CustomEnums.RecoilSnappiness, player.inventory.holdingItemItemValue, snappinessDefault, player); + //targetRotationXY = Vector2.Lerp(targetRotationXY, Vector2.zero, returnSpeed * Time.deltaTime); + float scaledDeltaTime = (Time.time - lastKickTime) * snappiness * 3; + Vector3 result = Vector3.Lerp(Vector3.zero, new Vector3(targetRotationXY.x, targetRotationXY.y), Mathf.Sin(Mathf.PI * .5f * Mathf.Lerp(0, 1, scaledDeltaTime))); + targetRotationXY -= new Vector2(result.x, result.y); + targetReturnXY += new Vector2(result.x, result.y); + player.movementInput.rotation += result; + if (scaledDeltaTime >= 1) + { + targetRotationXY = Vector3.zero; + returnSpeedCur = Vector3.zero; + state = RecoilState.Return; + } + } + else if (state == RecoilState.Return) + { + //Log.Out($"target return {targetReturnXY}"); + //if (targetReturnXY.sqrMagnitude <= 1e-6 && totalRotationXY.sqrMagnitude <= 1e-6) + //{ + // targetReturnXY = Vector3.zero; + // totalRotationXY = Vector2.zero; + // returnSpeedCur = Vector3.zero; + // totalReturnCur = Vector3.zero; + // //returnScaledDelta = 1; + // state = RecoilState.None; + // return; + //} + FastTags actionTags = player.inventory.holdingItemItemValue.ItemClass.ItemTags; + MultiActionManager.ModifyItemTags(player.inventory.holdingItemItemValue, player.inventory.holdingItemData.actionData[MultiActionManager.GetActionIndexForEntity(player)], ref actionTags); + float returnSpeedDefault; + if (actionTags.Test_AnySet(PistolTag)) + { + returnSpeedDefault = DEFAULT_RETURN_SPEED_PISTOL; + } + else if (actionTags.Test_AnySet(ShotgunTag)) + { + returnSpeedDefault = DEFAULT_RETURN_SPEED_SHOTGUN; + } + else + { + returnSpeedDefault = DEFAULT_RETURN_SPEED_RIFLE; + } + + float returnSpeed = EffectManager.GetValue(CustomEnums.RecoilReturnSpeed, player.inventory.holdingItemItemValue, returnSpeedDefault, player); + //returnScaledDelta += returnSpeed * Time.deltaTime; + Vector3 result = Vector3.SmoothDamp(Vector3.zero, new Vector3(targetReturnXY.x, targetReturnXY.y), ref returnSpeedCur, 1 / returnSpeed); + targetReturnXY -= new Vector2(result.x, result.y); + player.movementInput.rotation -= result; + if (enableCap) + { + result = Vector3.SmoothDamp(Vector3.zero, new Vector3(totalRotationXY.x, totalRotationXY.y), ref totalReturnCur, 4 / returnSpeed); + totalRotationXY -= new Vector2(result.x, result.y); + } + if (targetReturnXY.sqrMagnitude <= 1e-6 && totalRotationXY.sqrMagnitude <= 1e-6 && Time.time - lastKickTime >= 1 / returnSpeed) + { + targetReturnXY = Vector3.zero; + totalRotationXY = Vector2.zero; + returnSpeedCur = Vector3.zero; + totalReturnCur = Vector3.zero; + state = RecoilState.None; + } + } + else + { + ClearData(); + } + } + + private static float ApplyOppositeCompensation(float target, float mod, out float modRes) + { + //mouse movement come in with the same direction as recoil + if (mod * target >= 0) + { + modRes = mod; + return target; + } + float res = target + mod; + //is mouse movement enough to compensate the recoil? + if (res * target >= 0) + { + modRes = 0; + return res; + } + else + { + modRes = res; + return 0; + } + } + } +} diff --git a/Scripts/Utilities/EasingFunctions.cs b/Scripts/Utilities/EasingFunctions.cs new file mode 100644 index 0000000..f24a93d --- /dev/null +++ b/Scripts/Utilities/EasingFunctions.cs @@ -0,0 +1,125 @@ +using System; + +//https://gist.github.com/Kryzarel/bba64622057f21a1d6d44879f9cd7bd4 +namespace Kryz.Tweening +{ + // Made with the help of this great post: https://joshondesign.com/2013/03/01/improvedEasingEquations + + // --------------------------------- Other Related Links -------------------------------------------------------------------- + // Original equations, bad formulation: https://github.com/danro/jquery-easing/blob/master/jquery.easing.js + // A few equations, very simplified: https://gist.github.com/gre/1650294 + // Easings.net equations, simplified: https://github.com/ai/easings.net/blob/master/src/easings/easingsFunctions.ts + + public static class EasingFunctions + { + public static float Linear(float t) => t; + + public static float InQuad(float t) => t * t; + public static float OutQuad(float t) => 1 - InQuad(1 - t); + public static float InOutQuad(float t) + { + if (t < 0.5) return InQuad(t * 2) / 2; + return 1 - InQuad((1 - t) * 2) / 2; + } + + public static float InCubic(float t) => t * t * t; + public static float OutCubic(float t) => 1 - InCubic(1 - t); + public static float InOutCubic(float t) + { + if (t < 0.5) return InCubic(t * 2) / 2; + return 1 - InCubic((1 - t) * 2) / 2; + } + + public static float InQuart(float t) => t * t * t * t; + public static float OutQuart(float t) => 1 - InQuart(1 - t); + public static float InOutQuart(float t) + { + if (t < 0.5) return InQuart(t * 2) / 2; + return 1 - InQuart((1 - t) * 2) / 2; + } + + public static float InQuint(float t) => t * t * t * t * t; + public static float OutQuint(float t) => 1 - InQuint(1 - t); + public static float InOutQuint(float t) + { + if (t < 0.5) return InQuint(t * 2) / 2; + return 1 - InQuint((1 - t) * 2) / 2; + } + + public static float InSine(float t) => 1 - (float)Math.Cos(t * Math.PI / 2); + public static float OutSine(float t) => (float)Math.Sin(t * Math.PI / 2); + public static float InOutSine(float t) => (float)(Math.Cos(t * Math.PI) - 1) / -2; + + public static float InExpo(float t) => (float)Math.Pow(2, 10 * (t - 1)); + public static float OutExpo(float t) => 1 - InExpo(1 - t); + public static float InOutExpo(float t) + { + if (t < 0.5) return InExpo(t * 2) / 2; + return 1 - InExpo((1 - t) * 2) / 2; + } + + public static float InCirc(float t) => -((float)Math.Sqrt(1 - t * t) - 1); + public static float OutCirc(float t) => 1 - InCirc(1 - t); + public static float InOutCirc(float t) + { + if (t < 0.5) return InCirc(t * 2) / 2; + return 1 - InCirc((1 - t) * 2) / 2; + } + + public static float InElastic(float t) => 1 - OutElastic(1 - t); + public static float OutElastic(float t) + { + float p = 0.3f; + return (float)Math.Pow(2, -10 * t) * (float)Math.Sin((t - p / 4) * (2 * Math.PI) / p) + 1; + } + public static float InOutElastic(float t) + { + if (t < 0.5) return InElastic(t * 2) / 2; + return 1 - InElastic((1 - t) * 2) / 2; + } + + public static float InBack(float t) + { + float s = 1.70158f; + return t * t * ((s + 1) * t - s); + } + public static float OutBack(float t) => 1 - InBack(1 - t); + public static float InOutBack(float t) + { + if (t < 0.5) return InBack(t * 2) / 2; + return 1 - InBack((1 - t) * 2) / 2; + } + + public static float InBounce(float t) => 1 - OutBounce(1 - t); + public static float OutBounce(float t) + { + float div = 2.75f; + float mult = 7.5625f; + + if (t < 1 / div) + { + return mult * t * t; + } + else if (t < 2 / div) + { + t -= 1.5f / div; + return mult * t * t + 0.75f; + } + else if (t < 2.5 / div) + { + t -= 2.25f / div; + return mult * t * t + 0.9375f; + } + else + { + t -= 2.625f / div; + return mult * t * t + 0.984375f; + } + } + public static float InOutBounce(float t) + { + if (t < 0.5) return InBounce(t * 2) / 2; + return 1 - InBounce((1 - t) * 2) / 2; + } + } +} diff --git a/Scripts/Utilities/EntityInventoryExtension.cs b/Scripts/Utilities/EntityInventoryExtension.cs new file mode 100644 index 0000000..af07210 --- /dev/null +++ b/Scripts/Utilities/EntityInventoryExtension.cs @@ -0,0 +1,67 @@ +public static class EntityInventoryExtension +{ + public static void TryStackItem(this EntityAlive self, ItemStack stack) + { + if (self.bag.TryStackItem(stack)) + return; + self.inventory.TryStackItem(stack); + } + + public static void TryRemoveItem(this EntityAlive self, int count, ItemValue value) + { + int decFromInv = self.bag.DecItem(value, count) - count; + if (decFromInv > 0) + self.inventory.DecItem(value, decFromInv); + } + + public static int GetItemCount(this EntityAlive self, ItemValue value) + { + return self.inventory.GetItemCount(value) + self.bag.GetItemCount(value); + } + + public static bool TryStackItem(this Bag self, ItemStack stack) + { + ItemStack[] slots = self.GetSlots(); + TryStackItem(slots, stack); + self.SetSlots(slots); + return stack.count == 0; + } + + public static bool TryStackItem(this Inventory self, ItemStack stack) + { + ItemStack[] slots = self.GetSlots(); + TryStackItem(slots, stack); + self.CallOnToolbeltChangedInternal(); + return stack.count == 0; + } + + public static void TryStackWith(this ItemStack self, ItemStack other) + { + int maxStackCount = other.itemValue.ItemClass.Stacknumber.Value; + if (self.IsEmpty()) + { + self.itemValue = other.itemValue.Clone(); + self.count = Utils.FastMin(maxStackCount, other.count); + other.count -= self.count; + return; + } + + if (self.itemValue.type != other.itemValue.type || self.itemValue.Texture != other.itemValue.Texture || self.count >= maxStackCount) + return; + + int add = Utils.FastMin(maxStackCount - self.count, other.count); + self.count += add; + other.count -= add; + } + + private static void TryStackItem(ItemStack[] slots, ItemStack stack) + { + foreach (var slot in slots) + { + slot.TryStackWith(stack); + if (stack.count == 0) + return; + } + } +} + diff --git a/Scripts/Utilities/ExpressionParser/ExpressionParser.cs b/Scripts/Utilities/ExpressionParser/ExpressionParser.cs new file mode 100644 index 0000000..3495173 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/ExpressionParser.cs @@ -0,0 +1,424 @@ +using System; +using System.Collections.Generic; +using UniLinq; +using Sprache; +using static Sprache.Parse; + +namespace CodeWriter.ExpressionParser +{ + public delegate T Expression(); + + public abstract class ExpressionParser + { + private readonly Dictionary _builderCached = new Dictionary(); + private Parser _parserCached; + + public Expression CompilePredicate(string input, ExpressionContext context, bool cache) + { + var expr = Compile(input, context, cache); + return () => IsTrue(expr.Invoke()); + } + + public Expression Compile(string input, ExpressionContext context, bool cache) + { + context = context ?? new ExpressionContext(); + + _parserCached = _parserCached ?? CreateParser(); + + ExprBuilder builder; + try + { + if (cache) + { + if (!_builderCached.TryGetValue(input, out builder)) + { + builder = _parserCached.Parse(input); + _builderCached.Add(input, builder); + } + } + else + { + builder = _parserCached.Parse(input); + } + } + catch (ParseException parseException) + { + throw new ExpressionParseException(input, parseException); + } + + return builder.Invoke(context); + } + + private static Parser Operator(string op, BinaryFunc fun) + { + return String(op).Token().Return(fun).Named(op); + } + + private static Parser BinaryOperator(Parser op, + Parser operand, Func apply) => + ( + from l in operand + from rest in + ( + from f in op + from r in operand + select apply(f, l, r) + ).Optional() + select rest.IsEmpty ? l : rest.Get() + ); + + private Parser CreateParser() + { + var letterOrUnderscore = Char(c => char.IsLetter(c) || c == '_', + "letter or underscore"); + var letterOrDigitOrUnderscore = Char(c => char.IsLetterOrDigit(c) || c == '_', + "letter or digit or underscore"); + + var constant = ( + from number in DecimalInvariant + select MakeConstant(number, Parse) + ).Named("number"); + + var add = Operator("+", Add); + var sub = Operator("-", Sub); + var mul = Operator("*", Mul); + var div = Operator("/", Div); + var mod = Operator("%", Mod); + var pow = Operator("^", Pow); + var eq = Operator("=", Equal); + var neq = Operator("!=", NotEqual); + var and = Operator("AND", And); + var or = Operator("OR", Or); + var lt = Operator("<", LessThan); + var lte = Operator("<=", LessThanOrEqual); + var gt = Operator(">", GreaterThan); + var gte = Operator(">=", GreaterThanOrEqual); + + var variable = + ( + from nameHead in letterOrUnderscore.Once().Text() + from nameTail in letterOrDigitOrUnderscore.Many().Text() + select MakeVariable(nameHead + nameTail) + ).Named("variable"); + + Parser expression = null; + + var function = + ( + from name in Letter.AtLeastOnce().Text() + from lparen in Char('(') + // ReSharper disable once AccessToModifiedClosure + from expr in Ref(() => expression).DelimitedBy(Char(',').Token()) + from rparen in Char(')') + select MakeFunction(name, expr.ToList()) + ).Named("function"); + + var factor = + ( + from lparen in Char('(') + // ReSharper disable once AccessToModifiedClosure + from expr in Ref(() => expression) + from rparen in Char(')') + select expr + ).Named("expression") + .XOr(constant) + .XOr(function) + .Or(variable); + + var operand = + ( + ( + from sign in Char('-') + from fact in factor + select MakeUnary(Negate, fact) + ) + .XOr(factor) + ).Token(); + + var term1 = ChainRightOperator(pow, operand, MakeBinary); + var term2 = ChainOperator(mul.Or(div).Or(mod), term1, MakeBinary); + var term3 = ChainOperator(add.Or(sub), term2, MakeBinary); + var term4 = BinaryOperator(lte.Or(lt).Or(gte).Or(gt), term3, MakeBinary); + var term5 = BinaryOperator(eq.Or(neq), term4, MakeBinary); + var term6 = ChainOperator(and, term5, MakeBinary); + var term7 = ChainOperator(or, term6, MakeBinary); + + expression = term7; + + return expression.End(); + } + + protected abstract T False { get; } + protected abstract T True { get; } + + protected abstract T Parse(string input); + protected abstract T Negate(T v); + protected abstract T Add(T a, T b); + protected abstract T Sub(T a, T b); + protected abstract T Mul(T a, T b); + protected abstract T Div(T a, T b); + protected abstract T Mod(T a, T b); + protected abstract T Pow(T a, T b); + protected abstract T Equal(T a, T b); + protected abstract T NotEqual(T a, T b); + protected abstract T LessThan(T a, T b); + protected abstract T LessThanOrEqual(T a, T b); + protected abstract T GreaterThan(T a, T b); + protected abstract T GreaterThanOrEqual(T a, T b); + protected abstract bool IsTrue(T v); + + protected abstract T Round(T v); + protected abstract T Floor(T v); + protected abstract T Ceiling(T v); + protected abstract T Log10(T v); + + protected virtual T Log(T v, T newBase) => Div(Log10(v), Log10(newBase)); + + private T Not(T v) => IsTrue(v) ? False : True; + private T And(T a, T b) => IsTrue(a) ? b : a; + private T Or(T a, T b) => IsTrue(a) ? a : b; + private T Min(T a, T b) => IsTrue(GreaterThan(a, b)) ? b : a; + private T Max(T a, T b) => IsTrue(GreaterThan(b, a)) ? b : a; + + private delegate Expression ExprBuilder(ExpressionContext context); + + private delegate T UnaryFunc(T a); + + private delegate T BinaryFunc(T a, T b); + + private ExprBuilder MakeFunction(string name, List parameterBuilders) + { + switch (name) + { + case "NOT": + return MakeFunction1(Not); + + case "ROUND": + return MakeFunction1(Round); + + case "CEILING": + return MakeFunction1(Ceiling); + + case "FLOOR": + return MakeFunction1(Floor); + + case "LOG": + return parameterBuilders.Count == 2 + ? MakeBinary(Log, parameterBuilders[0], parameterBuilders[1]) + : MakeFunction1(Log10); + + case "MIN": + return MakeFunctionFold(Min); + + case "MAX": + return MakeFunctionFold(Max); + + case "IF": + if (parameterBuilders.Count < 3 || + parameterBuilders.Count % 2 != 1) + { + throw new FunctionNotDefinedException(name, "Wrong parameters count"); + } + + return context => + { + var conditions = new List>(); + var results = new List>(); + var defaultResult = parameterBuilders[parameterBuilders.Count - 1].Invoke(context); + + for (var i = 0; i < parameterBuilders.Count - 1; i += 2) + { + conditions.Add(parameterBuilders[i].Invoke(context)); + results.Add(parameterBuilders[i + 1].Invoke(context)); + } + + return () => + { + for (var i = 0; i < conditions.Count; i++) + { + if (IsTrue(conditions[i].Invoke())) + { + return results[i].Invoke(); + } + } + + return defaultResult.Invoke(); + }; + }; + + default: throw new FunctionNotDefinedException(name, "Unknown name"); + } + + ExprBuilder MakeFunction1(Func func) + { + if (parameterBuilders.Count != 1) + { + throw new FunctionNotDefinedException(name, "Wrong parameters count"); + } + + return context => + { + var inner = parameterBuilders[0].Invoke(context); + return () => func(inner.Invoke()); + }; + } + + ExprBuilder MakeFunctionFold(Func func) + { + if (parameterBuilders.Count < 1) + { + throw new FunctionNotDefinedException(name, "Wrong parameters count"); + } + + return context => + { + var inner = new List>(); + + for (var i = 0; i < parameterBuilders.Count; i++) + { + inner.Add(parameterBuilders[i].Invoke(context)); + } + + return () => + { + var result = inner[0].Invoke(); + for (var i = 1; i < inner.Count; i++) + { + result = func(result, inner[i].Invoke()); + } + + return result; + }; + }; + } + } + + private static ExprBuilder MakeUnary(UnaryFunc func, ExprBuilder innerBuilder) + { + return context => + { + var inner = innerBuilder.Invoke(context); + return () => func(inner.Invoke()); + }; + } + + private static ExprBuilder MakeBinary(BinaryFunc func, ExprBuilder l, ExprBuilder r) + { + return context => + { + var left = l.Invoke(context); + var right = r.Invoke(context); + return () => func(left.Invoke(), right.Invoke()); + }; + } + + private ExprBuilder MakeVariable(string name) + { + if (name.Equals("TRUE", StringComparison.Ordinal)) + { + return context => () => True; + } + + if (name.Equals("FALSE", StringComparison.Ordinal)) + { + return context => () => False; + } + + return context => + { + var variable = context.GetVariable(name); + return variable; + }; + } + + private static ExprBuilder MakeConstant(string valueString, Func parser) + { + var value = parser(valueString); + return context => () => value; + } + } + + public class ExpressionContext + { + private readonly ExpressionContext _parent; + private readonly Func> _unregisteredVariableResolver; + + private readonly Dictionary> _variables = new Dictionary>(); + + public ExpressionContext(ExpressionContext parent = null, + Func> unregisteredVariableResolver = null) + { + _parent = parent; + _unregisteredVariableResolver = unregisteredVariableResolver; + } + + public void RegisterVariable(string name, Expression value) + { + if (_variables.ContainsKey(name)) + { + throw new InvalidOperationException($"Variable {name} already registered"); + } + + _variables.Add(name, value); + } + + public Expression GetVariable(string name, bool nullIsOk = false) + { + if (_variables.TryGetValue(name, out var variable)) + { + return variable; + } + + if (_unregisteredVariableResolver != null) + { + variable = _unregisteredVariableResolver.Invoke(name); + if (variable != null) + { + return variable; + } + } + + var parentVariable = _parent?.GetVariable(name, nullIsOk: true); + if (parentVariable != null) + { + return parentVariable; + } + + if (nullIsOk) + { + return null; + } + + throw new VariableNotDefinedException(name); + } + } + + [Obsolete("ExpresionContext contains a typo. Use ExpressionContext instead", true)] + public class ExpresionContext : ExpressionContext + { + } + + public class VariableNotDefinedException : Exception + { + public VariableNotDefinedException(string name) + : base($"Variable '{name}' not defined") + { + } + } + + public class FunctionNotDefinedException : Exception + { + public FunctionNotDefinedException(string name, string reason) : base( + $"Function '{name}' not defined: {reason}") + { + } + } + + public class ExpressionParseException : Exception + { + public ExpressionParseException(string expression, ParseException parseException) + : base($"Failed to parse expression '{expression}'{Environment.NewLine}{parseException.Message}") + { + } + } +} \ No newline at end of file diff --git a/Scripts/Utilities/ExpressionParser/FloatExpressionParser.cs b/Scripts/Utilities/ExpressionParser/FloatExpressionParser.cs new file mode 100644 index 0000000..4b848c1 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/FloatExpressionParser.cs @@ -0,0 +1,38 @@ +using System; +using System.Globalization; +using UnityEngine; + +namespace CodeWriter.ExpressionParser +{ + public class FloatExpressionParser : ExpressionParser + { + public static readonly ExpressionParser Instance = new FloatExpressionParser(); + + protected override float False { get; } = 0f; + protected override float True { get; } = 1f; + + protected override float Parse(string input) => + float.Parse(input, NumberStyles.Any, CultureInfo.InvariantCulture); + + protected override float Negate(float v) => -v; + protected override float Add(float a, float b) => a + b; + protected override float Sub(float a, float b) => a - b; + protected override float Mul(float a, float b) => a * b; + protected override float Div(float a, float b) => a / b; + protected override float Mod(float a, float b) => a % b; + protected override float Pow(float a, float b) => Mathf.Pow(a, b); + protected override float Equal(float a, float b) => Mathf.Approximately(a, b) ? 1 : 0; + protected override float NotEqual(float a, float b) => !Mathf.Approximately(a, b) ? 1 : 0; + protected override float LessThan(float a, float b) => a < b ? 1 : 0; + protected override float LessThanOrEqual(float a, float b) => a <= b ? 1 : 0; + protected override float GreaterThan(float a, float b) => a > b ? 1 : 0; + protected override float GreaterThanOrEqual(float a, float b) => a >= b ? 1 : 0; + protected override bool IsTrue(float v) => !Mathf.Approximately(v, 0); + protected override float Round(float v) => (float) Math.Round(v); + protected override float Ceiling(float v) => (float) Math.Ceiling(v); + protected override float Floor(float v) => (float) Math.Floor(v); + protected override float Log10(float v) => (float) Math.Log10(v); + + protected override float Log(float v, float newBase) => (float) Math.Log(v, newBase); + } +} \ No newline at end of file diff --git a/Scripts/Utilities/ExpressionParser/Sprache/CommentParser.cs b/Scripts/Utilities/ExpressionParser/Sprache/CommentParser.cs new file mode 100644 index 0000000..2c003b3 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/CommentParser.cs @@ -0,0 +1,124 @@ +namespace Sprache +{ + /// + /// Constructs customizable comment parsers. + /// + public class CommentParser : IComment + { + /// + ///Single-line comment header. + /// + public string Single { get; set; } + + /// + ///Newline character preference. + /// + public string NewLine { get; set; } + + /// + ///Multi-line comment opener. + /// + public string MultiOpen { get; set; } + + /// + ///Multi-line comment closer. + /// + public string MultiClose { get; set; } + + /// + /// Initializes a Comment with C-style headers and Windows newlines. + /// + public CommentParser() + { + Single = "//"; + MultiOpen = "/*"; + MultiClose = "*/"; + NewLine = "\n"; + } + + /// + /// Initializes a Comment with custom multi-line headers and newline characters. + /// Single-line headers are made null, it is assumed they would not be used. + /// + /// + /// + /// + public CommentParser(string multiOpen, string multiClose, string newLine) + { + Single = null; + MultiOpen = multiOpen; + MultiClose = multiClose; + NewLine = newLine; + } + + /// + /// Initializes a Comment with custom headers and newline characters. + /// + /// + /// + /// + /// + public CommentParser(string single, string multiOpen, string multiClose, string newLine) + { + Single = single; + MultiOpen = multiOpen; + MultiClose = multiClose; + NewLine = newLine; + } + + /// + ///Parse a single-line comment. + /// + public Parser SingleLineComment + { + get + { + if (Single == null) + throw new ParseException("Field 'Single' is null; single-line comments not allowed."); + + return from first in Parse.String(Single) + from rest in Parse.CharExcept(NewLine).Many().Text() + select rest; + } + private set { } + } + + /// + ///Parse a multi-line comment. + /// + public Parser MultiLineComment + { + get + { + if (MultiOpen == null) + throw new ParseException("Field 'MultiOpen' is null; multi-line comments not allowed."); + else if (MultiClose == null) + throw new ParseException("Field 'MultiClose' is null; multi-line comments not allowed."); + + return from first in Parse.String(MultiOpen) + from rest in Parse.AnyChar + .Until(Parse.String(MultiClose)).Text() + select rest; + } + private set { } + } + + /// + ///Parse a comment. + /// + public Parser AnyComment + { + get + { + if (Single != null && MultiOpen != null && MultiClose != null) + return SingleLineComment.Or(MultiLineComment); + else if (Single != null && (MultiOpen == null || MultiClose == null)) + return SingleLineComment; + else if (Single == null && (MultiOpen != null && MultiClose != null)) + return MultiLineComment; + else throw new ParseException("Unable to parse comment; check values of fields 'MultiOpen' and 'MultiClose'."); + } + private set { } + } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/IComment.cs b/Scripts/Utilities/ExpressionParser/Sprache/IComment.cs new file mode 100644 index 0000000..039cb47 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/IComment.cs @@ -0,0 +1,43 @@ +namespace Sprache +{ + /// + /// Represents a customizable comment parser. + /// + public interface IComment + { + /// + /// Single-line comment header. + /// + string Single { get; set; } + + /// + /// Newline character preference. + /// + string NewLine { get; set; } + + /// + /// Multi-line comment opener. + /// + string MultiOpen { get; set; } + + /// + /// Multi-line comment closer. + /// + string MultiClose { get; set; } + + /// + /// Parse a single-line comment. + /// + Parser SingleLineComment { get; } + + /// + /// Parse a multi-line comment. + /// + Parser MultiLineComment { get; } + + /// + /// Parse a comment. + /// + Parser AnyComment { get; } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/ICommentedOfT.cs b/Scripts/Utilities/ExpressionParser/Sprache/ICommentedOfT.cs new file mode 100644 index 0000000..d4451a3 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/ICommentedOfT.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; + +namespace Sprache +{ + /// + /// Represents a commented result with its leading and trailing comments. + /// + /// Type of the matched result. + public interface ICommented + { + /// + /// Gets the leading comments. + /// + IEnumerable LeadingComments { get; } + + /// + /// Gets the resulting value. + /// + T Value { get; } + + /// + /// Gets the trailing comments. + /// + IEnumerable TrailingComments { get; } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/IInput.cs b/Scripts/Utilities/ExpressionParser/Sprache/IInput.cs new file mode 100644 index 0000000..b6c77c5 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/IInput.cs @@ -0,0 +1,53 @@ +using System; +using System.Collections.Generic; + +namespace Sprache +{ + /// + /// Represents an input for parsing. + /// + public interface IInput : IEquatable + { + /// + /// Advances the input. + /// + /// A new that is advanced. + /// The input is already at the end of the source. + IInput Advance(); + + /// + /// Gets the whole source. + /// + string Source { get; } + + /// + /// Gets the current . + /// + char Current { get; } + + /// + /// Gets a value indicating whether the end of the source is reached. + /// + bool AtEnd { get; } + + /// + /// Gets the current positon. + /// + int Position { get; } + + /// + /// Gets the current line number. + /// + int Line { get; } + + /// + /// Gets the current column. + /// + int Column { get; } + + /// + /// Memos used by this input + /// + IDictionary Memos { get; } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/IPositionAware.cs b/Scripts/Utilities/ExpressionParser/Sprache/IPositionAware.cs new file mode 100644 index 0000000..4434d10 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/IPositionAware.cs @@ -0,0 +1,18 @@ + +namespace Sprache +{ + /// + /// An interface for objects that have a source . + /// + /// Type of the matched result. + public interface IPositionAware + { + /// + /// Set the start and the matched length. + /// + /// The start position + /// The matched length. + /// The matched result. + T SetPos(Position startPos, int length); + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/IResultOfT.cs b/Scripts/Utilities/ExpressionParser/Sprache/IResultOfT.cs new file mode 100644 index 0000000..137e4bc --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/IResultOfT.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; + +namespace Sprache +{ + /// + /// Represents a parsing result. + /// + /// The result type. + public interface IResult + { + /// + /// Gets the resulting value. + /// + T Value { get; } + + /// + /// Gets a value indicating whether wether parsing was successful. + /// + bool WasSuccessful { get; } + + /// + /// Gets the error message. + /// + string Message { get; } + + /// + /// Gets the parser expectations in case of error. + /// + IEnumerable Expectations { get; } + + /// + /// Gets the remainder of the input. + /// + IInput Remainder { get; } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/ITextSpanOfT.cs b/Scripts/Utilities/ExpressionParser/Sprache/ITextSpanOfT.cs new file mode 100644 index 0000000..08ef5ac --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/ITextSpanOfT.cs @@ -0,0 +1,29 @@ +namespace Sprache +{ + /// + /// Represents a text span of the matched result. + /// + /// Type of the matched result. + public interface ITextSpan + { + /// + /// Gets the resulting value. + /// + T Value { get; } + + /// + /// Gets the starting . + /// + Position Start { get; } + + /// + /// Gets the ending . + /// + Position End { get; } + + /// + /// Gets the length of the text span. + /// + int Length { get; } + } +} \ No newline at end of file diff --git a/Scripts/Utilities/ExpressionParser/Sprache/Input.cs b/Scripts/Utilities/ExpressionParser/Sprache/Input.cs new file mode 100644 index 0000000..75d8ae9 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/Input.cs @@ -0,0 +1,156 @@ +using System; +using System.Collections.Generic; + +namespace Sprache +{ + /// + /// Represents an input for parsing. + /// + public class Input : IInput + { + private readonly string _source; + private readonly int _position; + private readonly int _line; + private readonly int _column; + + /// + /// Gets the list of memos assigned to the instance. + /// + public IDictionary Memos { get; private set; } + + /// + /// Initializes a new instance of the class. + /// + /// The source. + public Input(string source) + : this(source, 0) + { + } + + internal Input(string source, int position, int line = 1, int column = 1) + { + _source = source; + _position = position; + _line = line; + _column = column; + + Memos = new Dictionary(); + } + + /// + /// Advances the input. + /// + /// A new that is advanced. + /// The input is already at the end of the source. + public IInput Advance() + { + if (AtEnd) + throw new InvalidOperationException("The input is already at the end of the source."); + + return new Input(_source, _position + 1, Current == '\n' ? _line + 1 : _line, Current == '\n' ? 1 : _column + 1); + } + + /// + /// Gets the whole source. + /// + public string Source { get { return _source; } } + + /// + /// Gets the current . + /// + public char Current { get { return _source[_position]; } } + + /// + /// Gets a value indicating whether the end of the source is reached. + /// + public bool AtEnd { get { return _position == _source.Length; } } + + /// + /// Gets the current positon. + /// + public int Position { get { return _position; } } + + /// + /// Gets the current line number. + /// + public int Line { get { return _line; } } + + /// + /// Gets the current column. + /// + public int Column { get { return _column; } } + + /// + /// Returns a string that represents the current object. + /// + /// + /// A string that represents the current object. + /// + public override string ToString() + { + return string.Format("Line {0}, Column {1}", _line, _column); + } + + /// + /// Serves as a hash function for a particular type. + /// + /// + /// A hash code for the current . + /// + public override int GetHashCode() + { + unchecked + { + return ((_source != null ? _source.GetHashCode() : 0) * 397) ^ _position; + } + } + + /// + /// Determines whether the specified is equal to the current . + /// + /// + /// true if the specified is equal to the current ; otherwise, false. + /// + /// The object to compare with the current object. + public override bool Equals(object obj) + { + return Equals(obj as IInput); + } + + /// + /// Indicates whether the current is equal to another object of the same type. + /// + /// + /// true if the current object is equal to the parameter; otherwise, false. + /// + /// An object to compare with this object. + public bool Equals(IInput other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return string.Equals(_source, other.Source) && _position == other.Position; + } + + /// + /// Indicates whether the left is equal to the right . + /// + /// The left . + /// The right . + /// true if both objects are equal. + public static bool operator ==(Input left, Input right) + { + return Equals(left, right); + } + + /// + /// Indicates whether the left is not equal to the right . + /// + /// The left . + /// The right . + /// true if the objects are not equal. + public static bool operator !=(Input left, Input right) + { + return !Equals(left, right); + } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/Option.cs b/Scripts/Utilities/ExpressionParser/Sprache/Option.cs new file mode 100644 index 0000000..3f80b68 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/Option.cs @@ -0,0 +1,145 @@ +using System; + +namespace Sprache +{ + /// + /// Represents an optional result. + /// + /// The result type. + public interface IOption + { + /// + /// Gets a value indicating whether this instance is empty. + /// + bool IsEmpty { get; } + + /// + /// Gets a value indicating whether this instance is defined. + /// + bool IsDefined { get; } + + /// + /// Gets the matched result or a default value. + /// + /// + T GetOrDefault(); + + /// + /// Gets the matched result. + /// + T Get(); + } + + /// + /// Extensions for . + /// + public static class OptionExtensions + { + /// + /// Gets the value or else returns a default value. + /// + /// The result type. + /// + /// The default value. + /// + public static T GetOrElse(this IOption option, T defaultValue) + { + if (option == null) throw new ArgumentNullException(nameof(option)); + return option.IsEmpty ? defaultValue : option.Get(); + } + + /// + /// Maps a function over the value or else returns an empty option. + /// + /// The input type. + /// The output type. + /// The option containing the value to apply to. + /// The function to apply to the value of . + /// An options result containing the result if there was an input value. + public static IOption Select(this IOption option, Func map) + { + if (option == null) throw new ArgumentNullException(nameof(option)); + return option.IsDefined ? (IOption) new Some(map(option.Get())) : new None(); + } + + /// + /// Binds the value to a function with optional result and flattens the result to a single optional. + /// A result projection is applied aftherwards. + /// + /// The input type. + /// The output type of . + /// The final output type. + /// The option containing the value to bind to. + /// The function that receives the input values and returns an optional value. + /// The function that is projects the result of . + /// An option result containing the result if there were was an input value and bind result. + public static IOption SelectMany(this IOption option, Func> bind, Func project) + { + if (option == null) throw new ArgumentNullException(nameof(option)); + if (option.IsEmpty) return new None(); + + var t = option.Get(); + return bind(t).Select(u => project(t,u)); + } + + /// + /// Binds the value to a function with optional result and flattens the result to a single optional. + /// + /// The input type. + /// The output type. + /// The option containing the value to bind to. + /// The function that receives the input values and returns an optional value. + /// An option result containing the result if there were was an input value and bind result. + public static IOption SelectMany(this IOption option, Func> bind) => option.SelectMany(bind, (_,x) => x); + } + + internal abstract class AbstractOption : IOption + { + public abstract bool IsEmpty { get; } + + public bool IsDefined + { + get { return !IsEmpty; } + } + + public T GetOrDefault() + { + return IsEmpty ? default(T) : Get(); + } + + public abstract T Get(); + } + + internal sealed class Some : AbstractOption + { + private readonly T _value; + + public Some(T value) + { + _value = value; + } + + public override bool IsEmpty + { + get { return false; } + } + + public override T Get() + { + return _value; + } + } + + internal sealed class None : AbstractOption + { + public override bool IsEmpty + { + get { return true; } + } + + public override T Get() + { + throw new InvalidOperationException("Cannot get value from None."); + } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/Parse.Commented.cs b/Scripts/Utilities/ExpressionParser/Sprache/Parse.Commented.cs new file mode 100644 index 0000000..248dcc1 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/Parse.Commented.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using UniLinq; + +namespace Sprache +{ + partial class Parse + { + /// + /// Represents a text span of the matched result. + /// + /// Type of the matched result. + private class TextSpan : ITextSpan + { + public T Value { get; set; } + + public Position Start { get; set; } + + public Position End { get; set; } + + public int Length { get; set; } + } + + /// + /// Constructs a parser that returns the of the parsed value. + /// + /// The result type of the given parser. + /// The parser to wrap. + /// A parser for the text span of the given parser. + public static Parser> Span(this Parser parser) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return i => + { + var r = parser(i); + if (r.WasSuccessful) + { + var span = new TextSpan + { + Value = r.Value, + Start = Position.FromInput(i), + End = Position.FromInput(r.Remainder), + Length = r.Remainder.Position - i.Position, + }; + + return Result.Success(span, r.Remainder); + } + + return Result.Failure>(r.Remainder, r.Message, r.Expectations); + }; + } + + /// + /// Represents a commented result with its leading and trailing comments. + /// + /// Type of the matched result. + private class CommentedValue : ICommented + { + public CommentedValue(T value) + { + LeadingComments = TrailingComments = EmptyStringList; + Value = value; + } + + public CommentedValue(IEnumerable leading, T value, IEnumerable trailing) + { + LeadingComments = leading ?? EmptyStringList; + Value = value; + TrailingComments = trailing ?? EmptyStringList; + } + + public T Value { get; } + + public IEnumerable LeadingComments { get; } + + public IEnumerable TrailingComments { get; } + } + + private static readonly string[] EmptyStringList = new string[0]; + + private static readonly IComment DefaultCommentParser = new CommentParser(); + + /// + /// Constructs a parser that consumes a whitespace and all comments + /// parsed by the commentParser.AnyComment parser, but parses only one trailing + /// comment that starts exactly on the last line of the parsed value. + /// + /// The result type of the given parser. + /// The parser to wrap. + /// The comment parser. + /// An extended Token() version of the given parser. + public static Parser> Commented(this Parser parser, IComment commentParser = null) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + // consume any comment supported by the comment parser + var comment = (commentParser ?? DefaultCommentParser).AnyComment; + + // parses any whitespace except for the new lines + var whiteSpaceExceptForNewLine = WhiteSpace.Except(Chars("\r\n")).Many().Text(); + + // returns true if the second span starts on the first span's last line + bool IsSameLine(ITextSpan first, ITextSpan second) => + first.End.Line == second.Start.Line; + + // single comment span followed by a whitespace + var commentSpan = + from cs in comment.Span() + from ws in whiteSpaceExceptForNewLine + select cs; + + // add leading and trailing comments to the parser + return + from leadingWhiteSpace in WhiteSpace.Many() + from leadingComments in comment.Token().Many() + from valueSpan in parser.Span() + from trailingWhiteSpace in whiteSpaceExceptForNewLine + from trailingPreview in commentSpan.Many().Preview() + let trailingCount = trailingPreview.GetOrElse(Enumerable.Empty>()) + .Where(c => IsSameLine(valueSpan, c)).Count() + from trailingComments in commentSpan.Repeat(trailingCount) + select new CommentedValue(leadingComments, valueSpan.Value, trailingComments.Select(c => c.Value)); + } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/Parse.Optional.cs b/Scripts/Utilities/ExpressionParser/Sprache/Parse.Optional.cs new file mode 100644 index 0000000..87ed1ee --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/Parse.Optional.cs @@ -0,0 +1,80 @@ +using System; + +namespace Sprache +{ + partial class Parse + { + /// + /// Construct a parser that indicates that the given parser + /// is optional. The returned parser will succeed on + /// any input no matter whether the given parser + /// succeeds or not. + /// + /// The result type of the given parser. + /// The parser to wrap. + /// An optional version of the given parser. + public static Parser> Optional(this Parser parser) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return i => + { + var pr = parser(i); + + if (pr.WasSuccessful) + return Result.Success(new Some(pr.Value), pr.Remainder); + + return Result.Success(new None(), i); + }; + } + + /// + /// Constructs the eXclusive version of the Optional{T} parser. + /// + /// The result type of the given parser + /// The parser to wrap + /// An eXclusive optional version of the given parser. + /// + public static Parser> XOptional(this Parser parser) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return i => + { + var result = parser(i); + + if (result.WasSuccessful) + return Result.Success(new Some(result.Value), result.Remainder); + + if (result.Remainder.Equals(i)) + return Result.Success(new None(), i); + + return Result.Failure>(result.Remainder, result.Message, result.Expectations); + }; + } + + /// + /// Construct a parser that indicates that the given parser is optional + /// and non-consuming. The returned parser will succeed on + /// any input no matter whether the given parser succeeds or not. + /// In any case, it won't consume any input, like a positive look-ahead in regex. + /// + /// The result type of the given parser. + /// The parser to wrap. + /// A non-consuming version of the given parser. + public static Parser> Preview(this Parser parser) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return i => + { + var result = parser(i); + + if (result.WasSuccessful) + return Result.Success(new Some(result.Value), i); + + return Result.Success(new None(), i); + }; + } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/Parse.Positioned.cs b/Scripts/Utilities/ExpressionParser/Sprache/Parse.Positioned.cs new file mode 100644 index 0000000..2ded180 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/Parse.Positioned.cs @@ -0,0 +1,27 @@ + +namespace Sprache +{ + partial class Parse + { + /// + /// Construct a parser that will set the position to the position-aware + /// T on succsessful match. + /// + /// + /// + /// + public static Parser Positioned(this Parser parser) where T : IPositionAware + { + return i => + { + var r = parser(i); + + if (r.WasSuccessful) + { + return Result.Success(r.Value.SetPos(Position.FromInput(i), r.Remainder.Position - i.Position), r.Remainder); + } + return r; + }; + } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/Parse.Primitives.cs b/Scripts/Utilities/ExpressionParser/Sprache/Parse.Primitives.cs new file mode 100644 index 0000000..0b7b631 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/Parse.Primitives.cs @@ -0,0 +1,34 @@ +namespace Sprache +{ + partial class Parse + { + /// + /// \n or \r\n + /// + public static Parser LineEnd = + (from r in Char('\r').Optional() + from n in Char('\n') + select r.IsDefined ? r.Get().ToString() + n : n.ToString()) + .Named("LineEnd"); + + /// + /// line ending or end of input + /// + public static Parser LineTerminator = + Return("").End() + .Or(LineEnd.End()) + .Or(LineEnd) + .Named("LineTerminator"); + + /// + /// Parser for identifier starting with and continuing with + /// + public static Parser Identifier(Parser firstLetterParser, Parser tailLetterParser) + { + return + from firstLetter in firstLetterParser + from tail in tailLetterParser.Many().Text() + select firstLetter + tail; + } + } +} \ No newline at end of file diff --git a/Scripts/Utilities/ExpressionParser/Sprache/Parse.Sequence.cs b/Scripts/Utilities/ExpressionParser/Sprache/Parse.Sequence.cs new file mode 100644 index 0000000..819b565 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/Parse.Sequence.cs @@ -0,0 +1,158 @@ +namespace Sprache +{ + using System; + using System.Collections.Generic; + using UniLinq; + + partial class Parse + { + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static Parser> DelimitedBy(this Parser parser, Parser delimiter) + { + return DelimitedBy(parser, delimiter, null, null); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static Parser> DelimitedBy(this Parser parser, Parser delimiter, int? minimumCount, int? maximumCount) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + if (delimiter == null) throw new ArgumentNullException(nameof(delimiter)); + + return from head in parser.Once() + from tail in + (from separator in delimiter + from item in parser + select item).Repeat(minimumCount - 1, maximumCount - 1) + select head.Concat(tail); + } + + /// + /// Fails on the first itemParser failure, if it reads at least one character. + /// + /// + /// + /// + /// + /// + /// + public static Parser> XDelimitedBy(this Parser itemParser, Parser delimiter) + { + if (itemParser == null) throw new ArgumentNullException(nameof(itemParser)); + if (delimiter == null) throw new ArgumentNullException(nameof(delimiter)); + + return from head in itemParser.Once() + from tail in + (from separator in delimiter + from item in itemParser + select item).XMany() + select head.Concat(tail); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public static Parser> Repeat(this Parser parser, int count) + { + return Repeat(parser, count, count); + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static Parser> Repeat(this Parser parser, int? minimumCount, int? maximumCount) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return i => + { + var remainder = i; + var result = new List(); + + var count = 0; + + var r = parser(remainder); + while (r.WasSuccessful && (maximumCount == null || count < maximumCount.Value)) + { + count++; + + result.Add(r.Value); + + remainder = r.Remainder; + r = parser(remainder); + } + + if (minimumCount.HasValue && count < minimumCount.Value) + { + var what = r.Remainder.AtEnd + ? "end of input" + : r.Remainder.Current.ToString(); + + var msg = $"Unexpected '{what}'"; + string exp; + if (minimumCount == maximumCount) + exp = $"'{StringExtensions.Join(", ", r.Expectations)}' {minimumCount.Value} times, but found {count}"; + else if (maximumCount == null) + exp = $"'{StringExtensions.Join(", ", r.Expectations)}' minimum {minimumCount.Value} times, but found {count}"; + else + exp = $"'{StringExtensions.Join(", ", r.Expectations)}' between {minimumCount.Value} and {maximumCount.Value} times, but found {count}"; + + return Result.Failure>(i, msg, new[] { exp }); + } + + return Result.Success>(result, remainder); + }; + } + + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + /// + public static Parser Contained(this Parser parser, Parser open, Parser close) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + if (open == null) throw new ArgumentNullException(nameof(open)); + if (close == null) throw new ArgumentNullException(nameof(close)); + + return from o in open + from item in parser + from c in close + select item; + } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/Parse.cs b/Scripts/Utilities/ExpressionParser/Sprache/Parse.cs new file mode 100644 index 0000000..735802d --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/Parse.cs @@ -0,0 +1,782 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using UniLinq; + +namespace Sprache +{ + /// + /// Parsers and combinators. + /// + public static partial class Parse + { + /// + /// TryParse a single character matching 'predicate' + /// + /// + /// + /// + public static Parser Char(Predicate predicate, string description) + { + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + if (description == null) throw new ArgumentNullException(nameof(description)); + + return i => + { + if (!i.AtEnd) + { + if (predicate(i.Current)) + return Result.Success(i.Current, i.Advance()); + + return Result.Failure(i, + $"unexpected '{i.Current}'", + new[] { description }); + } + + return Result.Failure(i, + "Unexpected end of input reached", + new[] { description }); + }; + } + + /// + /// Parse a single character except those matching . + /// + /// Characters not to match. + /// Description of characters that don't match. + /// A parser for characters except those matching . + public static Parser CharExcept(Predicate predicate, string description) + { + return Char(c => !predicate(c), "any character except " + description); + } + + /// + /// Parse a single character c. + /// + /// + /// + public static Parser Char(char c) + { + return Char(ch => c == ch, char.ToString(c)); + } + + + /// + /// Parse a single character of any in c + /// + /// + /// + public static Parser Chars(params char[] c) + { + return Char(c.Contains, StringExtensions.Join("|", c)); + } + + /// + /// Parse a single character of any in c + /// + /// + /// + public static Parser Chars(string c) + { + return Char(c.ToEnumerable().Contains, StringExtensions.Join("|", c.ToEnumerable())); + } + + + /// + /// Parse a single character except c. + /// + /// + /// + public static Parser CharExcept(char c) + { + return CharExcept(ch => c == ch, char.ToString(c)); + } + + /// + /// Parses a single character except for those in the given parameters + /// + /// + /// + public static Parser CharExcept(IEnumerable c) + { + var chars = c as char[] ?? c.ToArray(); + return CharExcept(chars.Contains, StringExtensions.Join("|", chars)); + } + + /// + /// Parses a single character except for those in c + /// + /// + /// + public static Parser CharExcept(string c) + { + return CharExcept(c.ToEnumerable().Contains, StringExtensions.Join("|", c.ToEnumerable())); + } + + /// + /// Parse a single character in a case-insensitive fashion. + /// + /// + /// + public static Parser IgnoreCase(char c) + { + return Char(ch => char.ToLower(c) == char.ToLower(ch), char.ToString(c)); + } + + /// + /// Parse a string in a case-insensitive fashion. + /// + /// + /// + public static Parser> IgnoreCase(string s) + { + if (s == null) throw new ArgumentNullException(nameof(s)); + + return s + .ToEnumerable() + .Select(IgnoreCase) + .Aggregate(Return(Enumerable.Empty()), + (a, p) => a.Concat(p.Once())) + .Named(s); + } + + /// + /// Parse any character. + /// + public static readonly Parser AnyChar = Char(c => true, "any character"); + + /// + /// Parse a whitespace. + /// + public static readonly Parser WhiteSpace = Char(char.IsWhiteSpace, "whitespace"); + + /// + /// Parse a digit. + /// + public static readonly Parser Digit = Char(char.IsDigit, "digit"); + + /// + /// Parse a letter. + /// + public static readonly Parser Letter = Char(char.IsLetter, "letter"); + + /// + /// Parse a letter or digit. + /// + public static readonly Parser LetterOrDigit = Char(char.IsLetterOrDigit, "letter or digit"); + + /// + /// Parse a lowercase letter. + /// + public static readonly Parser Lower = Char(char.IsLower, "lowercase letter"); + + /// + /// Parse an uppercase letter. + /// + public static readonly Parser Upper = Char(char.IsUpper, "uppercase letter"); + + /// + /// Parse a numeric character. + /// + public static readonly Parser Numeric = Char(char.IsNumber, "numeric character"); + + /// + /// Parse a string of characters. + /// + /// + /// + public static Parser> String(string s) + { + if (s == null) throw new ArgumentNullException(nameof(s)); + + return s + .ToEnumerable() + .Select(Char) + .Aggregate(Return(Enumerable.Empty()), + (a, p) => a.Concat(p.Once())) + .Named(s); + } + + /// + /// Constructs a parser that will fail if the given parser succeeds, + /// and will succeed if the given parser fails. In any case, it won't + /// consume any input. It's like a negative look-ahead in regex. + /// + /// The result type of the given parser + /// The parser to wrap + /// A parser that is the opposite of the given parser. + public static Parser Not(this Parser parser) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return i => + { + var result = parser(i); + + if (result.WasSuccessful) + { + var msg = $"`{StringExtensions.Join(", ", result.Expectations)}' was not expected"; + return Result.Failure(i, msg, new string[0]); + } + return Result.Success(null, i); + }; + } + + /// + /// Parse first, and if successful, then parse second. + /// + /// + /// + /// + /// + /// + public static Parser Then(this Parser first, Func> second) + { + if (first == null) throw new ArgumentNullException(nameof(first)); + if (second == null) throw new ArgumentNullException(nameof(second)); + + return i => first(i).IfSuccess(s => second(s.Value)(s.Remainder)); + } + + /// + /// Parse a stream of elements. + /// + /// + /// + /// + /// Implemented imperatively to decrease stack usage. + public static Parser> Many(this Parser parser) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return i => + { + var remainder = i; + var result = new List(); + var r = parser(i); + + while (r.WasSuccessful) + { + if (remainder.Equals(r.Remainder)) + break; + + result.Add(r.Value); + remainder = r.Remainder; + r = parser(remainder); + } + + return Result.Success>(result, remainder); + }; + } + + /// + /// Parse a stream of elements, failing if any element is only partially parsed. + /// + /// The type of element to parse. + /// A parser that matches a single element. + /// A that matches the sequence. + /// + /// + /// Using may be preferable to + /// where the first character of each match identified by + /// is sufficient to determine whether the entire match should succeed. The X* + /// methods typically give more helpful errors and are easier to debug than their + /// unqualified counterparts. + /// + /// + /// + public static Parser> XMany(this Parser parser) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return parser.Many().Then(m => parser.Once().XOr(Return(m))); + } + + /// + /// TryParse a stream of elements with at least one item. + /// + /// + /// + /// + public static Parser> AtLeastOnce(this Parser parser) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return parser.Once().Then(t1 => parser.Many().Select(ts => t1.Concat(ts))); + } + + /// + /// TryParse a stream of elements with at least one item. Except the first + /// item, all other items will be matched with the XMany operator. + /// + /// + /// + /// + public static Parser> XAtLeastOnce(this Parser parser) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return parser.Once().Then(t1 => parser.XMany().Select(ts => t1.Concat(ts))); + } + + /// + /// Parse end-of-input. + /// + /// + /// + /// + public static Parser End(this Parser parser) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return i => parser(i).IfSuccess(s => + s.Remainder.AtEnd + ? s + : Result.Failure( + s.Remainder, + string.Format("unexpected '{0}'", s.Remainder.Current), + new[] { "end of input" })); + } + + /// + /// Take the result of parsing, and project it onto a different domain. + /// + /// + /// + /// + /// + /// + public static Parser Select(this Parser parser, Func convert) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + if (convert == null) throw new ArgumentNullException(nameof(convert)); + + return parser.Then(t => Return(convert(t))); + } + + /// + /// Parse the token, embedded in any amount of whitespace characters. + /// + /// + /// + /// + public static Parser Token(this Parser parser) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return from leading in WhiteSpace.Many() + from item in parser + from trailing in WhiteSpace.Many() + select item; + } + + /// + /// Refer to another parser indirectly. This allows circular compile-time dependency between parsers. + /// + /// + /// + /// + public static Parser Ref(Func> reference) + { + if (reference == null) throw new ArgumentNullException(nameof(reference)); + + Parser p = null; + + return i => + { + if (p == null) + p = reference(); + + if (i.Memos.ContainsKey(p)) + { + var pResult = i.Memos[p] as IResult; + if (pResult.WasSuccessful) + return pResult; + throw new ParseException(pResult.ToString()); + } + + i.Memos[p] = Result.Failure(i, + "Left recursion in the grammar.", + new string[0]); + var result = p(i); + i.Memos[p] = result; + return result; + }; + } + + /// + /// Convert a stream of characters to a string. + /// + /// + /// + public static Parser Text(this Parser> characters) + { + return characters.Select(chs => new string(chs.ToArray())); + } + + /// + /// Parse first, if it succeeds, return first, otherwise try second. + /// + /// + /// + /// + /// + public static Parser Or(this Parser first, Parser second) + { + if (first == null) throw new ArgumentNullException(nameof(first)); + if (second == null) throw new ArgumentNullException(nameof(second)); + + return i => + { + var fr = first(i); + if (!fr.WasSuccessful) + { + return second(i).IfFailure(sf => DetermineBestError(fr, sf)); + } + + if (fr.Remainder.Equals(i)) + return second(i).IfFailure(sf => fr); + + return fr; + }; + } + + /// + /// Names part of the grammar for help with error messages. + /// + /// + /// + /// + /// + public static Parser Named(this Parser parser, string name) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + if (name == null) throw new ArgumentNullException(nameof(name)); + + return i => parser(i).IfFailure(f => f.Remainder.Equals(i) ? + Result.Failure(f.Remainder, f.Message, new[] { name }) : + f); + } + + /// + /// Parse first, if it succeeds, return first, otherwise try second. + /// Assumes that the first parsed character will determine the parser chosen (see Try). + /// + /// + /// + /// + /// + public static Parser XOr(this Parser first, Parser second) + { + if (first == null) throw new ArgumentNullException(nameof(first)); + if (second == null) throw new ArgumentNullException(nameof(second)); + + return i => { + var fr = first(i); + if (!fr.WasSuccessful) + { + // The 'X' part + if (!fr.Remainder.Equals(i)) + return fr; + + return second(i).IfFailure(sf => DetermineBestError(fr, sf)); + } + + // This handles a zero-length successful application of first. + if (fr.Remainder.Equals(i)) + return second(i).IfFailure(sf => fr); + + return fr; + }; + } + + // Examines two results presumably obtained at an "Or" junction; returns the result with + // the most information, or if they apply at the same input position, a union of the results. + static IResult DetermineBestError(IResult firstFailure, IResult secondFailure) + { + if (secondFailure.Remainder.Position > firstFailure.Remainder.Position) + return secondFailure; + + if (secondFailure.Remainder.Position == firstFailure.Remainder.Position) + return Result.Failure( + firstFailure.Remainder, + firstFailure.Message, + firstFailure.Expectations.Union(secondFailure.Expectations)); + + return firstFailure; + } + + /// + /// Parse a stream of elements containing only one item. + /// + /// + /// + /// + public static Parser> Once(this Parser parser) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + + return parser.Select(r => (IEnumerable)new[] { r }); + } + + /// + /// Concatenate two streams of elements. + /// + /// + /// + /// + /// + public static Parser> Concat(this Parser> first, Parser> second) + { + if (first == null) throw new ArgumentNullException(nameof(first)); + if (second == null) throw new ArgumentNullException(nameof(second)); + + return first.Then(f => second.Select(f.Concat)); + } + + /// + /// Succeed immediately and return value. + /// + /// + /// + /// + public static Parser Return(T value) + { + return i => Result.Success(value, i); + } + + /// + /// Version of Return with simpler inline syntax. + /// + /// + /// + /// + /// + /// + public static Parser Return(this Parser parser, U value) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + return parser.Select(t => value); + } + + /// + /// Attempt parsing only if the parser fails. + /// + /// + /// + /// + /// + /// + public static Parser Except(this Parser parser, Parser except) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + if (except == null) throw new ArgumentNullException(nameof(except)); + + // Could be more like: except.Then(s => s.Fail("..")).XOr(parser) + return i => + { + var r = except(i); + if (r.WasSuccessful) + return Result.Failure(i, "Excepted parser succeeded.", new[] { "other than the excepted input" }); + return parser(i); + }; + } + + /// + /// Parse a sequence of items until a terminator is reached. + /// Returns the sequence, discarding the terminator. + /// + /// + /// + /// + /// + /// + public static Parser> Until(this Parser parser, Parser until) + { + return parser.Except(until).Many().Then(r => until.Return(r)); + } + + /// + /// Succeed if the parsed value matches predicate. + /// + /// + /// + /// + /// + public static Parser Where(this Parser parser, Func predicate) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + + return i => parser(i).IfSuccess(s => + predicate(s.Value) ? s : Result.Failure(i, + string.Format("Unexpected {0}.", s.Value), + new string[0])); + } + + /// + /// Monadic combinator Then, adapted for Linq comprehension syntax. + /// + /// + /// + /// + /// + /// + /// + /// + public static Parser SelectMany( + this Parser parser, + Func> selector, + Func projector) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + if (selector == null) throw new ArgumentNullException(nameof(selector)); + if (projector == null) throw new ArgumentNullException(nameof(projector)); + + return parser.Then(t => selector(t).Select(u => projector(t, u))); + } + + /// + /// Chain a left-associative operator. + /// + /// + /// + /// + /// + /// + /// + public static Parser ChainOperator( + Parser op, + Parser operand, + Func apply) + { + if (op == null) throw new ArgumentNullException(nameof(op)); + if (operand == null) throw new ArgumentNullException(nameof(operand)); + if (apply == null) throw new ArgumentNullException(nameof(apply)); + return operand.Then(first => ChainOperatorRest(first, op, operand, apply, Or)); + } + + /// + /// Chain a left-associative operator. + /// + /// + /// + /// + /// + /// + /// + public static Parser XChainOperator( + Parser op, + Parser operand, + Func apply) + { + if (op == null) throw new ArgumentNullException(nameof(op)); + if (operand == null) throw new ArgumentNullException(nameof(operand)); + if (apply == null) throw new ArgumentNullException(nameof(apply)); + return operand.Then(first => ChainOperatorRest(first, op, operand, apply, XOr)); + } + + static Parser ChainOperatorRest( + T firstOperand, + Parser op, + Parser operand, + Func apply, + Func, Parser, Parser> or) + { + if (op == null) throw new ArgumentNullException(nameof(op)); + if (operand == null) throw new ArgumentNullException(nameof(operand)); + if (apply == null) throw new ArgumentNullException(nameof(apply)); + return or(op.Then(opvalue => + operand.Then(operandValue => + ChainOperatorRest(apply(opvalue, firstOperand, operandValue), op, operand, apply, or))), + Return(firstOperand)); + } + + /// + /// Chain a right-associative operator. + /// + /// + /// + /// + /// + /// + /// + public static Parser ChainRightOperator( + Parser op, + Parser operand, + Func apply) + { + if (op == null) throw new ArgumentNullException(nameof(op)); + if (operand == null) throw new ArgumentNullException(nameof(operand)); + if (apply == null) throw new ArgumentNullException(nameof(apply)); + return operand.Then(first => ChainRightOperatorRest(first, op, operand, apply, Or)); + } + + /// + /// Chain a right-associative operator. + /// + /// + /// + /// + /// + /// + /// + public static Parser XChainRightOperator( + Parser op, + Parser operand, + Func apply) + { + if (op == null) throw new ArgumentNullException(nameof(op)); + if (operand == null) throw new ArgumentNullException(nameof(operand)); + if (apply == null) throw new ArgumentNullException(nameof(apply)); + return operand.Then(first => ChainRightOperatorRest(first, op, operand, apply, XOr)); + } + + static Parser ChainRightOperatorRest( + T lastOperand, + Parser op, + Parser operand, + Func apply, + Func, Parser, Parser> or) + { + if (op == null) throw new ArgumentNullException(nameof(op)); + if (operand == null) throw new ArgumentNullException(nameof(operand)); + if (apply == null) throw new ArgumentNullException(nameof(apply)); + return or(op.Then(opvalue => + operand.Then(operandValue => + ChainRightOperatorRest(operandValue, op, operand, apply, or)).Then(r => + Return(apply(opvalue, lastOperand, r)))), + Return(lastOperand)); + } + + /// + /// Parse a number. + /// + public static readonly Parser Number = Numeric.AtLeastOnce().Text(); + + static Parser DecimalWithoutLeadingDigits(CultureInfo ci = null) + { + return from nothing in Return("") + // dummy so that CultureInfo.CurrentCulture is evaluated later + from dot in String((ci ?? CultureInfo.CurrentCulture).NumberFormat.NumberDecimalSeparator).Text() + from fraction in Number + select dot + fraction; + } + + static Parser DecimalWithLeadingDigits(CultureInfo ci = null) + { + return Number.Then(n => DecimalWithoutLeadingDigits(ci).XOr(Return("")).Select(f => n + f)); + } + + /// + /// Parse a decimal number using the current culture's separator character. + /// + public static readonly Parser Decimal = DecimalWithLeadingDigits().XOr(DecimalWithoutLeadingDigits()); + + /// + /// Parse a decimal number with separator '.'. + /// + public static readonly Parser DecimalInvariant = DecimalWithLeadingDigits(CultureInfo.InvariantCulture) + .XOr(DecimalWithoutLeadingDigits(CultureInfo.InvariantCulture)); + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/ParseException.cs b/Scripts/Utilities/ExpressionParser/Sprache/ParseException.cs new file mode 100644 index 0000000..0de7f61 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/ParseException.cs @@ -0,0 +1,50 @@ +using System; + +namespace Sprache +{ + /// + /// Represents an error that occurs during parsing. + /// + public class ParseException : Exception + { + /// + /// Initializes a new instance of the class. + /// + public ParseException() { } + + /// + /// Initializes a new instance of the class with a specified error message. + /// + /// The message that describes the error. + public ParseException(string message) : base(message) { } + + /// + /// Initializes a new instance of the class with a specified error message + /// and the position where the error occured. + /// + /// The message that describes the error. + /// The position where the error occured. + public ParseException(string message, Position position) : base(message) + { + if (position == null) throw new ArgumentNullException(nameof(position)); + + Position = position; + } + + /// + /// Initializes a new instance of the class with a specified error message + /// and a reference to the inner exception that is the cause of this exception. + /// + /// The error message that explains the reason for the exception. + /// The exception that is the cause of the current exception, + /// or a null reference (Nothing in Visual Basic) if no inner exception is specified. + public ParseException(string message, Exception innerException) : base(message, innerException) { } + + /// + /// Gets the position of the parsing failure if one is available; otherwise, null. + /// + public Position Position { + get; + } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/ParserOfT.cs b/Scripts/Utilities/ExpressionParser/Sprache/ParserOfT.cs new file mode 100644 index 0000000..ebcce83 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/ParserOfT.cs @@ -0,0 +1,54 @@ +using System; + +namespace Sprache +{ + /// + /// Represents a parser. + /// + /// The type of the result. + /// The input to parse. + /// The result of the parser. + public delegate IResult Parser(IInput input); + + /// + /// Contains some extension methods for . + /// + public static class ParserExtensions + { + /// + /// Tries to parse the input without throwing an exception. + /// + /// The type of the result. + /// The parser. + /// The input. + /// The result of the parser + public static IResult TryParse(this Parser parser, string input) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + if (input == null) throw new ArgumentNullException(nameof(input)); + + return parser(new Input(input)); + } + + /// + /// Parses the specified input string. + /// + /// The type of the result. + /// The parser. + /// The input. + /// The result of the parser. + /// It contains the details of the parsing error. + public static T Parse(this Parser parser, string input) + { + if (parser == null) throw new ArgumentNullException(nameof(parser)); + if (input == null) throw new ArgumentNullException(nameof(input)); + + var result = parser.TryParse(input); + + if(result.WasSuccessful) + return result.Value; + + throw new ParseException(result.ToString(), Position.FromInput(result.Remainder)); + } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/Position.cs b/Scripts/Utilities/ExpressionParser/Sprache/Position.cs new file mode 100644 index 0000000..a300dc0 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/Position.cs @@ -0,0 +1,136 @@ +using System; + +namespace Sprache +{ + /// + /// Represents a position in the input. + /// + public class Position : IEquatable + { + /// + /// Initializes a new instance of the class. + /// + /// The position. + /// The line number. + /// The column. + public Position(int pos, int line, int column) + { + Pos = pos; + Line = line; + Column = column; + } + + /// + /// Creates an new instance from a given object. + /// + /// The current input. + /// A new instance. + public static Position FromInput(IInput input) + { + return new Position(input.Position, input.Line, input.Column); + } + + /// + /// Gets the current positon. + /// + public int Pos + { + get; + private set; + } + + /// + /// Gets the current line number. + /// + public int Line + { + get; + private set; + } + + /// + /// Gets the current column. + /// + public int Column + { + get; + private set; + } + + /// + /// Determines whether the specified is equal to the current . + /// + /// + /// true if the specified is equal to the current ; otherwise, false. + /// + /// The object to compare with the current object. + public override bool Equals(object obj) + { + return Equals(obj as Position); + } + + /// + /// Indicates whether the current is equal to another object of the same type. + /// + /// + /// true if the current object is equal to the parameter; otherwise, false. + /// + /// An object to compare with this object. + public bool Equals(Position other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + return Pos == other.Pos + && Line == other.Line + && Column == other.Column; + } + + /// + /// Indicates whether the left is equal to the right . + /// + /// The left . + /// The right . + /// true if both objects are equal. + public static bool operator ==(Position left, Position right) + { + return Equals(left, right); + } + + /// + /// Indicates whether the left is not equal to the right . + /// + /// The left . + /// The right . + /// true if the objects are not equal. + public static bool operator !=(Position left, Position right) + { + return !Equals(left, right); + } + + /// + /// Serves as a hash function for a particular type. + /// + /// + /// A hash code for the current . + /// + public override int GetHashCode() + { + var h = 31; + h = h * 13 + Pos; + h = h * 13 + Line; + h = h * 13 + Column; + return h; + } + + /// + /// Returns a string that represents the current object. + /// + /// + /// A string that represents the current object. + /// + public override string ToString() + { + return string.Format("Line {0}, Column {1}", Line, Column); + } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/Result.cs b/Scripts/Utilities/ExpressionParser/Sprache/Result.cs new file mode 100644 index 0000000..9e3908b --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/Result.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using UniLinq; + +namespace Sprache +{ + /// + /// Contains helper functions to create instances. + /// + public static class Result + { + /// + /// Creates a success result. + /// + /// The type of the result (value). + /// The sucessfully parsed value. + /// The remainder of the input. + /// The new . + public static IResult Success(T value, IInput remainder) + { + return new Result(value, remainder); + } + + /// + /// Creates a failure result. + /// + /// The type of the result. + /// The remainder of the input. + /// The error message. + /// The parser expectations. + /// The new . + public static IResult Failure(IInput remainder, string message, IEnumerable expectations) + { + return new Result(remainder, message, expectations); + } + } + + internal class Result : IResult + { + private readonly T _value; + private readonly IInput _remainder; + private readonly bool _wasSuccessful; + private readonly string _message; + private readonly IEnumerable _expectations; + + public Result(T value, IInput remainder) + { + _value = value; + _remainder = remainder; + _wasSuccessful = true; + _message = null; + _expectations = Enumerable.Empty(); + } + + public Result(IInput remainder, string message, IEnumerable expectations) + { + _value = default(T); + _remainder = remainder; + _wasSuccessful = false; + _message = message; + _expectations = expectations; + } + + public T Value + { + get + { + if (!WasSuccessful) + throw new InvalidOperationException("No value can be computed."); + + return _value; + } + } + + public bool WasSuccessful { get { return _wasSuccessful; } } + + public string Message { get { return _message; } } + + public IEnumerable Expectations { get { return _expectations; } } + + public IInput Remainder { get { return _remainder; } } + + public override string ToString() + { + if (WasSuccessful) + return string.Format("Successful parsing of {0}.", Value); + + var expMsg = ""; + + if (Expectations.Any()) + expMsg = " expected " + Expectations.Aggregate((e1, e2) => e1 + " or " + e2); + + var recentlyConsumed = CalculateRecentlyConsumed(); + + return string.Format("Parsing failure: {0};{1} ({2}); recently consumed: {3}", Message, expMsg, Remainder, recentlyConsumed); + } + + private string CalculateRecentlyConsumed() + { + const int windowSize = 10; + + var totalConsumedChars = Remainder.Position; + var windowStart = totalConsumedChars - windowSize; + windowStart = windowStart < 0 ? 0 : windowStart; + + var numberOfRecentlyConsumedChars = totalConsumedChars - windowStart; + + return Remainder.Source.Substring(windowStart, numberOfRecentlyConsumedChars); + } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/ResultHelper.cs b/Scripts/Utilities/ExpressionParser/Sprache/ResultHelper.cs new file mode 100644 index 0000000..72a3dc1 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/ResultHelper.cs @@ -0,0 +1,26 @@ +using System; + +namespace Sprache +{ + internal static class ResultHelper + { + public static IResult IfSuccess(this IResult result, Func, IResult> next) + { + if(result == null) throw new ArgumentNullException(nameof(result)); + + if (result.WasSuccessful) + return next(result); + + return Result.Failure(result.Remainder, result.Message, result.Expectations); + } + + public static IResult IfFailure(this IResult result, Func, IResult> next) + { + if (result == null) throw new ArgumentNullException(nameof(result)); + + return result.WasSuccessful + ? result + : next(result); + } + } +} \ No newline at end of file diff --git a/Scripts/Utilities/ExpressionParser/Sprache/StringExtensions.cs b/Scripts/Utilities/ExpressionParser/Sprache/StringExtensions.cs new file mode 100644 index 0000000..d8c1607 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/StringExtensions.cs @@ -0,0 +1,32 @@ +using System; +using System.Collections.Generic; +using UniLinq; + +namespace Sprache +{ + internal static class StringExtensions + { + public static IEnumerable ToEnumerable(this string @this) + { +#if STRING_IS_ENUMERABLE + return @this; +#else + if (@this == null) throw new ArgumentNullException(nameof(@this)); + + for (var i = 0; i < @this.Length; ++i) + { + yield return @this[i]; + } +#endif + } + + public static string Join(string separator, IEnumerable values) + { +#if STRING_JOIN_ENUMERABLE + return string.Join(separator, values); +#else + return string.Join(separator, values.Select(v => v.ToString()).ToArray()); +#endif + } + } +} diff --git a/Scripts/Utilities/ExpressionParser/Sprache/licence.txt b/Scripts/Utilities/ExpressionParser/Sprache/licence.txt new file mode 100644 index 0000000..fe2caa2 --- /dev/null +++ b/Scripts/Utilities/ExpressionParser/Sprache/licence.txt @@ -0,0 +1,21 @@ +The MIT License + +Copyright (c) 2011 Nicholas Blumhardt + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/Scripts/Utilities/Modular/IModuleProcessor.cs b/Scripts/Utilities/Modular/IModuleProcessor.cs new file mode 100644 index 0000000..59248f8 --- /dev/null +++ b/Scripts/Utilities/Modular/IModuleProcessor.cs @@ -0,0 +1,19 @@ +using KFCommonUtilityLib.Scripts.StaticManagers; +using Mono.Cecil.Cil; +using Mono.Cecil; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KFCommonUtilityLib +{ + public interface IModuleProcessor + { + void InitModules(ModuleManipulator manipulator, Type targetType, Type baseType, params Type[] moduleTypes); + bool BuildConstructor(ModuleManipulator manipulator, MethodDefinition mtddef_ctor); + Type GetModuleTypeByName(string name); + bool MatchSpecialArgs(ParameterDefinition par, MethodDefinition mtddef_target, MethodPatchInfo mtdpinf_derived, int moduleIndex, List list_inst_pars, ILProcessor il); + } +} diff --git a/Scripts/Utilities/Modular/ItemActionDataModuleProcessor.cs b/Scripts/Utilities/Modular/ItemActionDataModuleProcessor.cs new file mode 100644 index 0000000..e85a0f1 --- /dev/null +++ b/Scripts/Utilities/Modular/ItemActionDataModuleProcessor.cs @@ -0,0 +1,80 @@ +using Mono.Cecil; +using Mono.Cecil.Cil; +using System; +using System.Collections.Generic; + +namespace KFCommonUtilityLib +{ + public class ItemActionDataModuleProcessor : IModuleProcessor + { + TypeDefinition typedef_newAction; + Type[] arr_type_actions; + FieldDefinition[] arr_flddef_actions; + bool[] arr_hasdata; + FieldDefinition[] arr_flddef_actiondatas; + public ItemActionDataModuleProcessor(TypeDefinition typedef_newAction, Type[] arr_type_actions, FieldDefinition[] arr_flddef_actions, bool[] arr_hasdata, out FieldDefinition[] arr_flddef_actiondatas) + { + this.typedef_newAction = typedef_newAction; + this.arr_type_actions = arr_type_actions; + this.arr_flddef_actions = arr_flddef_actions; + this.arr_hasdata = arr_hasdata; + this.arr_flddef_actiondatas = new FieldDefinition[arr_type_actions.Length]; + arr_flddef_actiondatas = this.arr_flddef_actiondatas; + } + + public bool BuildConstructor(ModuleManipulator manipulator, MethodDefinition mtddef_ctor) + { + mtddef_ctor.Parameters.Add(new ParameterDefinition("_inventoryData", Mono.Cecil.ParameterAttributes.None, manipulator.module.ImportReference(typeof(ItemInventoryData)))); + mtddef_ctor.Parameters.Add(new ParameterDefinition("_indexInEntityOfAction", Mono.Cecil.ParameterAttributes.None, manipulator.module.TypeSystem.Int32)); + FieldReference fldref_invdata_item = manipulator.module.ImportReference(typeof(ItemInventoryData).GetField(nameof(ItemInventoryData.item))); + FieldReference fldref_item_actions = manipulator.module.ImportReference(typeof(ItemClass).GetField(nameof(ItemClass.Actions))); + var il = mtddef_ctor.Body.GetILProcessor(); + il.Append(il.Create(OpCodes.Ldarg_0)); + il.Append(il.Create(OpCodes.Ldarg_1)); + il.Append(il.Create(OpCodes.Ldarg_2)); + il.Append(il.Create(OpCodes.Call, manipulator.module.ImportReference(manipulator.targetType.GetConstructor(new Type[] { typeof(ItemInventoryData), typeof(int) })))); + il.Append(il.Create(OpCodes.Nop)); + for (int i = 0, j = 0; i < arr_type_actions.Length; i++) + { + if (!arr_hasdata[i]) + { + arr_flddef_actiondatas[i] = null; + continue; + } + arr_flddef_actiondatas[i] = manipulator.arr_flddef_modules[j]; + il.Append(il.Create(OpCodes.Ldarg_0)); + il.Append(il.Create(OpCodes.Ldarg_1)); + il.Append(il.Create(OpCodes.Ldarg_2)); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldfld, fldref_invdata_item); + il.Emit(OpCodes.Ldfld, fldref_item_actions); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Ldelem_Ref); + il.Emit(OpCodes.Castclass, typedef_newAction); + il.Emit(OpCodes.Ldfld, arr_flddef_actions[i]); + Log.Out($"data module {j} {manipulator.moduleTypes[j].FullName} action module {i} {arr_type_actions[i].FullName}"); + il.Append(il.Create(OpCodes.Newobj, manipulator.module.ImportReference(manipulator.moduleTypes[j].GetConstructor(new Type[] { typeof(ItemInventoryData), typeof(int), arr_type_actions[i] })))); + il.Append(il.Create(OpCodes.Stfld, manipulator.arr_flddef_modules[j])); + il.Append(il.Create(OpCodes.Nop)); + j++; + } + il.Append(il.Create(OpCodes.Ret)); + return true; + } + + public Type GetModuleTypeByName(string name) + { + throw new NotImplementedException(); + } + + public void InitModules(ModuleManipulator manipulator, Type targetType, Type baseType, params Type[] moduleTypes) + { + + } + + public bool MatchSpecialArgs(ParameterDefinition par, MethodDefinition mtddef_target, MethodPatchInfo mtdpinf_derived, int moduleIndex, List list_inst_pars, ILProcessor il) + { + return false; + } + } +} diff --git a/Scripts/Utilities/Modular/ItemActionModuleManager.cs b/Scripts/Utilities/Modular/ItemActionModuleManager.cs new file mode 100644 index 0000000..d2ae4a9 --- /dev/null +++ b/Scripts/Utilities/Modular/ItemActionModuleManager.cs @@ -0,0 +1,104 @@ +using KFCommonUtilityLib.Scripts.Attributes; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using UniLinq; + +namespace KFCommonUtilityLib +{ + //public static class AssemblyLocator + //{ + // private static Dictionary assemblies; + + // public static void Init() + // { + // assemblies = new Dictionary(); + // foreach (var assembly in ModManager.GetLoadedAssemblies()) + // { + // assemblies.Add(assembly.FullName, assembly); + // } + // AppDomain.CurrentDomain.AssemblyLoad += new AssemblyLoadEventHandler(CurrentDomain_AssemblyLoad); + // AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve); + // } + + // private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) + // { + // assemblies.TryGetValue(args.Name, out Assembly assembly); + // if (assembly != null) + // Log.Out($"RESOLVING ASSEMBLY {assembly.FullName}"); + // else + // Log.Error($"RESOLVING ASSEMBBLY {args.Name} FAILED!"); + // return assembly; + // } + + // private static void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs args) + // { + // Assembly assembly = args.LoadedAssembly; + // assemblies[assembly.FullName] = assembly; + // Log.Out($"LOADING ASSEMBLY {assembly.FullName}"); + // } + //} + + public static class ItemActionModuleManager + { + private static readonly Dictionary> dict_replacement_mapping = new Dictionary>(); + + internal static void Init() + { + ModuleManagers.OnAssemblyCreated += static () => dict_replacement_mapping.Clear(); + ModuleManagers.OnAssemblyLoaded += static () => + { + //replace item actions + foreach (var pair in dict_replacement_mapping) + { + ItemClass item = ItemClass.GetItemClass(pair.Key, true); + foreach ((string typename, int indexOfAction) in pair.Value) + if (ModuleManagers.TryFindType(typename, out Type itemActionType)) + { + //Log.Out($"Replace ItemAction {item.Actions[indexOfAction].GetType().FullName} with {itemActionType.FullName}"); + ItemAction itemActionPrev = item.Actions[indexOfAction]; + item.Actions[indexOfAction] = (ItemAction)Activator.CreateInstance(itemActionType); + item.Actions[indexOfAction].ActionIndex = indexOfAction; + item.Actions[indexOfAction].item = item; + item.Actions[indexOfAction].ExecutionRequirements = itemActionPrev.ExecutionRequirements; + item.Actions[indexOfAction].ReadFrom(itemActionPrev.Properties); + } + } + dict_replacement_mapping.Clear(); + }; + } + + internal static void CheckItem(ItemClass item) + { + if (!ModuleManagers.Inited) + { + return; + } + for (int i = 0; i < item.Actions.Length; i++) + { + ItemAction itemAction = item.Actions[i]; + if (itemAction != null && itemAction.Properties.Values.TryGetValue("ItemActionModules", out string str_modules)) + { + try + { + if (ModuleManagers.PatchType(itemAction.GetType(), typeof(ItemAction), str_modules, out string typename)) + { + if (!dict_replacement_mapping.TryGetValue(item.Name, out var list)) + { + list = new List<(string typename, int indexOfAction)>(); + dict_replacement_mapping.Add(item.Name, list); + } + list.Add((typename, i)); + } + } + catch(Exception e) + { + Log.Error($"Error parsing ItemActionModules for {item.Name} action{i}:\n{e}"); + continue; + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Utilities/Modular/ItemActionModuleProcessor.cs b/Scripts/Utilities/Modular/ItemActionModuleProcessor.cs new file mode 100644 index 0000000..b975dcf --- /dev/null +++ b/Scripts/Utilities/Modular/ItemActionModuleProcessor.cs @@ -0,0 +1,157 @@ +using Mono.Cecil; +using Mono.Cecil.Cil; +using System; +using System.Collections.Generic; +using UniLinq; +using System.Reflection; +using UnityEngine.Scripting; +using FieldAttributes = Mono.Cecil.FieldAttributes; +using MethodAttributes = Mono.Cecil.MethodAttributes; +using TypeAttributes = Mono.Cecil.TypeAttributes; +using KFCommonUtilityLib.Scripts.Attributes; +using Mono.Cecil.Rocks; + +namespace KFCommonUtilityLib +{ + public class ItemActionModuleProcessor : IModuleProcessor + { + TypeDefinition typedef_newActionData; + FieldDefinition[] arr_flddef_data; + + public Type GetModuleTypeByName(string name) + { + return ReflectionHelpers.GetTypeWithPrefix("ActionModule", name); + } + + public bool BuildConstructor(ModuleManipulator manipulator, MethodDefinition mtddef_ctor) + { + return false; + } + + public void InitModules(ModuleManipulator manipulator, Type targetType, Type baseType, params Type[] moduleTypes) + { + ModuleDefinition module = manipulator.module; + //Find ItemActionData subtype + MethodInfo mtdinf_create_data = null; + { + Type type_itemActionBase = targetType; + while (baseType.IsAssignableFrom(type_itemActionBase)) + { + mtdinf_create_data = type_itemActionBase.GetMethod(nameof(ItemAction.CreateModifierData), BindingFlags.Public | BindingFlags.Instance); + if (mtdinf_create_data != null) + break; + mtdinf_create_data = mtdinf_create_data.GetBaseDefinition(); + } + } + + //ACTION MODULE DATA TYPES + var arr_type_data = moduleTypes.Select(m => m.GetCustomAttribute()?.DataType).ToArray(); + //Create new ItemActionData + //Find CreateModifierData + MethodDefinition mtddef_create_data = module.ImportReference(mtdinf_create_data).Resolve(); + //ItemActionData subtype is the return type of CreateModifierData + TypeReference typeref_actiondata = ((MethodReference)mtddef_create_data.Body.Instructions[mtddef_create_data.Body.Instructions.Count - 2].Operand).DeclaringType; + //Get type by assembly qualified name since it might be from mod assembly + Type type_itemActionData = Type.GetType(Assembly.CreateQualifiedName(typeref_actiondata.Module.Assembly.Name.Name, typeref_actiondata.FullName)); + MethodReference mtdref_data_ctor; + if (ModuleManagers.PatchType(type_itemActionData, typeof(ItemActionData), arr_type_data.Where(t => t != null).ToArray(), new ItemActionDataModuleProcessor(manipulator.typedef_newTarget, moduleTypes, manipulator.arr_flddef_modules, arr_type_data.Select(t => t != null).ToArray(), out arr_flddef_data), out var str_data_type_name) && ModuleManagers.TryFindInCur(str_data_type_name, out typedef_newActionData)) + { + module.Types.Remove(typedef_newActionData); + manipulator.typedef_newTarget.NestedTypes.Add(typedef_newActionData); + mtdref_data_ctor = typedef_newActionData.GetConstructors().FirstOrDefault(); + } + else + { + mtdref_data_ctor = module.ImportReference(type_itemActionData.GetConstructor(new Type[] { typeof(ItemInventoryData), typeof(int) })); + } + + //typedef_newActionData = new TypeDefinition(null, ModuleUtils.CreateTypeName(type_itemActionData, arr_type_data), TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.NestedPublic | TypeAttributes.Sealed, module.ImportReference(typeref_actiondata)); + //typedef_newActionData.CustomAttributes.Add(new CustomAttribute(module.ImportReference(typeof(PreserveAttribute).GetConstructor(Array.Empty())))); + //manipulator.typedef_newTarget.NestedTypes.Add(typedef_newActionData); + + ////Create ItemActionData field + //arr_flddef_data = new FieldDefinition[moduleTypes.Length]; + //for (int i = 0; i < moduleTypes.Length; i++) + //{ + // if (arr_type_data[i] != null) + // { + // Type type_data = arr_type_data[i]; + // manipulator.MakeContainerFor(typedef_newActionData, type_data, out var flddef_data); + // arr_flddef_data[i] = flddef_data; + // } + //} + + ////Create ItemActionData constructor + //MethodDefinition mtddef_ctor_data = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, module.TypeSystem.Void); + //mtddef_ctor_data.Parameters.Add(new ParameterDefinition("_inventoryData", Mono.Cecil.ParameterAttributes.None, module.ImportReference(typeof(ItemInventoryData)))); + //mtddef_ctor_data.Parameters.Add(new ParameterDefinition("_indexInEntityOfAction", Mono.Cecil.ParameterAttributes.None, module.TypeSystem.Int32)); + //FieldReference fldref_invdata_item = module.ImportReference(typeof(ItemInventoryData).GetField(nameof(ItemInventoryData.item))); + //FieldReference fldref_item_actions = module.ImportReference(typeof(ItemClass).GetField(nameof(ItemClass.Actions))); + //var il = mtddef_ctor_data.Body.GetILProcessor(); + //il.Append(il.Create(OpCodes.Ldarg_0)); + //il.Append(il.Create(OpCodes.Ldarg_1)); + //il.Append(il.Create(OpCodes.Ldarg_2)); + //il.Append(il.Create(OpCodes.Call, module.ImportReference(type_itemActionData.GetConstructor(new Type[] { typeof(ItemInventoryData), typeof(int) })))); + //il.Append(il.Create(OpCodes.Nop)); + //for (int i = 0; i < arr_flddef_data.Length; i++) + //{ + // if (arr_type_data[i] == null) + // continue; + // il.Append(il.Create(OpCodes.Ldarg_0)); + // il.Append(il.Create(OpCodes.Ldarg_1)); + // il.Append(il.Create(OpCodes.Ldarg_2)); + // il.Emit(OpCodes.Ldarg_1); + // il.Emit(OpCodes.Ldfld, fldref_invdata_item); + // il.Emit(OpCodes.Ldfld, fldref_item_actions); + // il.Emit(OpCodes.Ldarg_2); + // il.Emit(OpCodes.Ldelem_Ref); + // il.Emit(OpCodes.Castclass, manipulator.typedef_newTarget); + // il.Emit(OpCodes.Ldfld, manipulator.arr_flddef_modules[i]); + // il.Append(il.Create(OpCodes.Newobj, module.ImportReference(arr_type_data[i].GetConstructor(new Type[] { typeof(ItemInventoryData), typeof(int), moduleTypes[i] })))); + // il.Append(il.Create(OpCodes.Stfld, arr_flddef_data[i])); + // il.Append(il.Create(OpCodes.Nop)); + //} + //il.Append(il.Create(OpCodes.Ret)); + //typedef_newActionData.Methods.Add(mtddef_ctor_data); + + //Create ItemAction.CreateModifierData override + MethodDefinition mtddef_create_modifier_data = new MethodDefinition(nameof(ItemAction.CreateModifierData), MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot, module.ImportReference(typeof(ItemActionData))); + mtddef_create_modifier_data.Parameters.Add(new ParameterDefinition("_invData", Mono.Cecil.ParameterAttributes.None, module.ImportReference(typeof(ItemInventoryData)))); + mtddef_create_modifier_data.Parameters.Add(new ParameterDefinition("_indexInEntityOfAction", Mono.Cecil.ParameterAttributes.None, module.TypeSystem.Int32)); + var il = mtddef_create_modifier_data.Body.GetILProcessor(); + il.Emit(OpCodes.Ldarg_1); + il.Emit(OpCodes.Ldarg_2); + il.Emit(OpCodes.Newobj, mtdref_data_ctor); + il.Emit(OpCodes.Ret); + manipulator.typedef_newTarget.Methods.Add(mtddef_create_modifier_data); + } + + public bool MatchSpecialArgs(ParameterDefinition par, MethodDefinition mtddef_target, MethodPatchInfo mtdpinf_derived, int moduleIndex, List list_inst_pars, ILProcessor il) + { + switch (par.Name) + { + //load injected data instance + case "__customData": + var flddef_data = arr_flddef_data[moduleIndex]; + if (flddef_data == null) + throw new ArgumentNullException($"No Injected ItemActionData in {mtddef_target.DeclaringType.FullName}! module index {moduleIndex}"); + int index = -1; + for (int j = 0; j < mtdpinf_derived.Method.Parameters.Count; j++) + { + if (mtdpinf_derived.Method.Parameters[j].ParameterType.Name == "ItemActionData") + { + index = j; + break; + } + } + if (index < 0) + throw new ArgumentException($"ItemActionData is not present in target method! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + list_inst_pars.Add(il.Create(OpCodes.Ldarg_S, mtdpinf_derived.Method.Parameters[index])); + list_inst_pars.Add(il.Create(OpCodes.Castclass, typedef_newActionData)); + list_inst_pars.Add(il.Create(par.ParameterType.IsByReference ? OpCodes.Ldflda : OpCodes.Ldfld, flddef_data)); + return true; + } + return false; + } + } +} diff --git a/Scripts/Utilities/Modular/ItemClassModuleManager.cs b/Scripts/Utilities/Modular/ItemClassModuleManager.cs new file mode 100644 index 0000000..e624ed8 --- /dev/null +++ b/Scripts/Utilities/Modular/ItemClassModuleManager.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; + +namespace KFCommonUtilityLib +{ + public static class ItemClassModuleManager + { + private static readonly Dictionary dict_classtypes = new Dictionary(); + + internal static void Init() + { + ModuleManagers.OnAssemblyCreated += static () => dict_classtypes.Clear(); + ModuleManagers.OnAssemblyLoaded += static () => + { + foreach (var pair in dict_classtypes) + { + if (ModuleManagers.TryFindType(pair.Value, out Type classType)) + { + var item = ItemClass.GetItemClass(pair.Key); + if (item != null) + { + var itemNew = (ItemClass)Activator.CreateInstance(classType); + item.PreInitCopyTo(itemNew); + if (item is ItemClassModifier mod) + { + mod.PreInitCopyToModifier((ItemClassModifier)itemNew); + } + itemNew.Init(); + ItemClass.itemNames.RemoveAt(ItemClass.itemNames.Count - 1); + ItemClass.list[itemNew.Id] = itemNew; + } + } + } + dict_classtypes.Clear(); + }; + } + + internal static void CheckItem(ItemClass item) + { + if (!ModuleManagers.Inited) + { + return; + } + + if (item != null && item.Properties.Values.TryGetValue("ItemClassModules", out string str_modules)) + { + if (ModuleManagers.PatchType(item.GetType(), typeof(ItemClass), str_modules, out string typename)) + { + dict_classtypes[item.Name] = typename; + } + } + } + + private static void PreInitCopyTo(this ItemClass from, ItemClass to) + { + to.Actions = from.Actions; + foreach (var action in to.Actions) + { + if (action != null) + { + action.item = to; + } + } + to.SetName(from.Name); + to.pId = from.pId; + to.Properties = from.Properties; + to.Effects = from.Effects; + to.setLocalizedItemName(from.localizedName); + to.Stacknumber = from.Stacknumber; + to.SetCanHold(from.bCanHold); + to.SetCanDrop(from.bCanDrop); + to.MadeOfMaterial = from.MadeOfMaterial; + to.MeshFile = from.MeshFile; + to.StickyOffset = from.StickyOffset; + to.StickyColliderRadius = from.StickyColliderRadius; + to.StickyColliderUp = from.StickyColliderUp; + to.StickyColliderLength = from.StickyColliderLength; + to.StickyMaterial = from.StickyMaterial; + to.ImageEffectOnActive = from.ImageEffectOnActive; + to.Active = from.Active; + to.IsSticky = from.IsSticky; + to.DropMeshFile = from.DropMeshFile; + to.HandMeshFile = from.HandMeshFile; + to.HoldType = from.HoldType; + to.RepairTools = from.RepairTools; + to.RepairAmount = from.RepairAmount; + to.RepairTime = from.RepairTime; + to.MaxUseTimes = from.MaxUseTimes; + to.MaxUseTimesBreaksAfter = from.MaxUseTimesBreaksAfter; + to.EconomicValue = from.EconomicValue; + to.Preview = from.Preview; + } + + private static void PreInitCopyToModifier(this ItemClassModifier from, ItemClassModifier to) + { + to.CosmeticInstallChance = from.CosmeticInstallChance; + to.PropertyOverrides = from.PropertyOverrides; + to.InstallableTags = from.InstallableTags; + to.DisallowedTags = from.DisallowedTags; + to.ItemTags = from.ItemTags; + to.Type = from.Type; + } + } +} diff --git a/Scripts/Utilities/Modular/ItemClassModuleProcessor.cs b/Scripts/Utilities/Modular/ItemClassModuleProcessor.cs new file mode 100644 index 0000000..065d0da --- /dev/null +++ b/Scripts/Utilities/Modular/ItemClassModuleProcessor.cs @@ -0,0 +1,33 @@ +using Mono.Cecil; +using Mono.Cecil.Cil; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KFCommonUtilityLib +{ + public struct ItemClassModuleProcessor : IModuleProcessor + { + + public Type GetModuleTypeByName(string name) + { + return ReflectionHelpers.GetTypeWithPrefix("ItemModule", name); + } + public bool BuildConstructor(ModuleManipulator manipulator, MethodDefinition mtddef_ctor) + { + return false; + } + + public void InitModules(ModuleManipulator manipulator, Type targetType, Type baseType, params Type[] moduleTypes) + { + + } + + public bool MatchSpecialArgs(ParameterDefinition par, MethodDefinition mtddef_target, MethodPatchInfo mtdpinf_derived, int moduleIndex, List list_inst_pars, ILProcessor il) + { + return false; + } + } +} diff --git a/Scripts/Utilities/Modular/ModuleManagers.cs b/Scripts/Utilities/Modular/ModuleManagers.cs new file mode 100644 index 0000000..e8c22c7 --- /dev/null +++ b/Scripts/Utilities/Modular/ModuleManagers.cs @@ -0,0 +1,262 @@ +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using Mono.Cecil; +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Security.Permissions; +using UniLinq; +using UnityEngine; + +namespace KFCommonUtilityLib +{ + public static class ModuleManagers + { + private static class ModuleExtensions + { + public readonly static List extensions = new List(); + } + public static AssemblyDefinition WorkingAssembly { get; private set; } = null; + public static event Action OnAssemblyCreated; + public static event Action OnAssemblyLoaded; + public static bool Inited { get; private set; } + private static bool extensionScanned; + private static readonly HashSet list_registered_path = new HashSet(); + private static readonly List list_created = new List(); + private static DefaultAssemblyResolver resolver; + private static ModuleAttributes moduleAttributes; + private static ModuleCharacteristics moduleCharacteristics; + private static MethodInfo mtdinf = AccessTools.Method(typeof(ModuleManagers), nameof(ModuleManagers.AddModuleExtension)); + + public static void InitModuleExtensions() + { + if (extensionScanned) + { + return; + } + var assemblies = ModManager.GetLoadedAssemblies(); + + foreach (var assembly in assemblies) + { + foreach (var type in assembly.GetTypes()) + { + var attr = type.GetCustomAttribute(); + if (attr != null) + { + if ((bool)mtdinf.MakeGenericMethod(attr.ModuleType).Invoke(null, new object[] { type })) + { + Log.Out($"Found Module Extension {type.FullName}"); + } + } + } + } + extensionScanned = true; + } + + public static bool AddModuleExtension(Type extType) + { + if (typeof(T).GetCustomAttribute() == null) + { + return false; + } + + if (!ModuleExtensions.extensions.Contains(extType)) + ModuleExtensions.extensions.Add(extType); + return true; + } + + public static Type[] GetModuleExtensions() + { + if (typeof(T).GetCustomAttribute() == null) + { + return Array.Empty(); + } + + return ModuleExtensions.extensions.ToArray(); + } + + public static void AddAssemblySearchPath(string path) + { + if (Directory.Exists(path)) + { + list_registered_path.Add(path); + } + } + + internal static void ClearOutputFolder() + { + Mod self = ModManager.GetMod("CommonUtilityLib"); + string path = Path.Combine(self.Path, "AssemblyOutput"); + if (Directory.Exists(path)) + Array.ForEach(Directory.GetFiles(path), File.Delete); + else + Directory.CreateDirectory(path); + } + + internal static void InitNew() + { + if (Inited) + { + return; + } + InitModuleExtensions(); + WorkingAssembly?.Dispose(); + if (resolver == null) + { + resolver = new DefaultAssemblyResolver(); + resolver.AddSearchDirectory(Path.Combine(Application.dataPath, "Managed")); + + foreach (var mod in ModManager.GetLoadedMods()) + { + resolver.AddSearchDirectory(mod.Path); + } + + foreach (var path in list_registered_path) + { + resolver.AddSearchDirectory(path); + } + + AssemblyDefinition assdef_main = AssemblyDefinition.ReadAssembly($"{Application.dataPath}/Managed/Assembly-CSharp.dll", new ReaderParameters() { AssemblyResolver = resolver }); + moduleAttributes = assdef_main.MainModule.Attributes; + moduleCharacteristics = assdef_main.MainModule.Characteristics; + Log.Out("Reading Attributes from assembly: " + assdef_main.FullName); + } + string assname = "RuntimeAssembled" + DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(); + WorkingAssembly = AssemblyDefinition.CreateAssembly(new AssemblyNameDefinition(assname, + new Version(0, 0, 0, 0)), + assname + ".dll", + new ModuleParameters() + { + Kind = ModuleKind.Dll, + AssemblyResolver = resolver, + Architecture = TargetArchitecture.I386, + Runtime = TargetRuntime.Net_4_0, + }); + WorkingAssembly.MainModule.Attributes = moduleAttributes; + WorkingAssembly.MainModule.Characteristics = moduleCharacteristics; + //write security attributes so that calling non-public patch methods from this assembly is allowed + Mono.Cecil.SecurityAttribute sattr_permission = new Mono.Cecil.SecurityAttribute(WorkingAssembly.MainModule.ImportReference(typeof(SecurityPermissionAttribute))); + Mono.Cecil.CustomAttributeNamedArgument caarg_SkipVerification = new Mono.Cecil.CustomAttributeNamedArgument(nameof(SecurityPermissionAttribute.SkipVerification), new CustomAttributeArgument(WorkingAssembly.MainModule.TypeSystem.Boolean, true)); + sattr_permission.Properties.Add(caarg_SkipVerification); + SecurityDeclaration sdec = new SecurityDeclaration(Mono.Cecil.SecurityAction.RequestMinimum); + sdec.SecurityAttributes.Add(sattr_permission); + WorkingAssembly.SecurityDeclarations.Add(sdec); + OnAssemblyCreated?.Invoke(); + Inited = true; + Log.Out("======Init New======"); + } + + public static bool PatchType(Type targetType, Type baseType, string moduleNames, out string typename) where T : IModuleProcessor, new() + { + Type[] moduleTypes = moduleNames.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) + .Select(s => new T().GetModuleTypeByName(s.Trim())) + .Where(t => t.GetCustomAttribute().BaseType.IsAssignableFrom(targetType)).ToArray(); + return PatchType(targetType, baseType, moduleTypes, new T(), out typename); + } + + public static bool PatchType(Type targetType, Type baseType, Type[] moduleTypes, out string typename) where T : IModuleProcessor, new() + { + return PatchType(targetType, baseType, moduleTypes, new T(), out typename); + } + + public static bool PatchType(Type targetType, Type baseType, Type[] moduleTypes, T processor, out string typename) where T : IModuleProcessor + { + if (moduleTypes.Length == 0) + { + typename = string.Empty; + return false; + } + typename = ModuleUtils.CreateTypeName(targetType, moduleTypes); + //Log.Out(typename); + if (!ModuleManagers.TryFindType(typename, out _) && !ModuleManagers.TryFindInCur(typename, out _)) + _ = new ModuleManipulator(ModuleManagers.WorkingAssembly, processor, targetType, baseType, moduleTypes); + return true; + } + + internal static void FinishAndLoad() + { + if (!Inited) + { + return; + } + //output assembly + Mod self = ModManager.GetMod("CommonUtilityLib"); + if (self == null) + { + Log.Warning("Failed to get mod!"); + self = ModManager.GetModForAssembly(typeof(ItemActionModuleManager).Assembly); + } + if (self != null && WorkingAssembly != null) + { + if (WorkingAssembly.MainModule.Types.Count > 1) + { + Log.Out("Assembly is valid!"); + using (MemoryStream ms = new MemoryStream()) + { + try + { + WorkingAssembly.Write(ms); + } + catch (Exception) + { + new ConsoleCmdShutdown().Execute(new List(), new CommandSenderInfo()); + } + DirectoryInfo dirInfo = Directory.CreateDirectory(Path.Combine(self.Path, "AssemblyOutput")); + string filename = Path.Combine(dirInfo.FullName, WorkingAssembly.Name.Name + ".dll"); + Log.Out("Output Assembly: " + filename); + using (FileStream fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write)) + { + ms.WriteTo(fs); + } + Assembly newAssembly = Assembly.LoadFile(filename); + list_created.Add(newAssembly); + } + } + + Log.Out("======Finish and Load======"); + Inited = false; + OnAssemblyLoaded?.Invoke(); + Cleanup(); + } + } + + //cleanup + internal static void Cleanup() + { + Inited = false; + WorkingAssembly?.Dispose(); + WorkingAssembly = null; + } + + /// + /// Check if type is already generated in previous assemblies. + /// + /// Full type name. + /// The retrieved type, null if not found. + /// true if found. + public static bool TryFindType(string name, out Type type) + { + type = null; + foreach (var assembly in list_created) + { + type = assembly.GetType(name, false); + if (type != null) + return true; + } + return false; + } + + /// + /// Check if type is already generated in current working assembly definition. + /// + /// Full type name. + /// The retrieved type definition, null if not found. + /// true if found. + public static bool TryFindInCur(string name, out TypeDefinition typedef) + { + typedef = WorkingAssembly?.MainModule.GetType(name); + return typedef != null; + } + } +} diff --git a/Scripts/Utilities/Modular/ModuleManipulator.cs b/Scripts/Utilities/Modular/ModuleManipulator.cs new file mode 100644 index 0000000..033fc2b --- /dev/null +++ b/Scripts/Utilities/Modular/ModuleManipulator.cs @@ -0,0 +1,646 @@ +using HarmonyLib.Public.Patching; +using HarmonyLib; +using KFCommonUtilityLib.Scripts.Attributes; +using Mono.Cecil; +using Mono.Cecil.Cil; +using MonoMod.Cil; +using MonoMod.Utils; +using System; +using System.Collections.Generic; +using UniLinq; +using System.Reflection; +using KFCommonUtilityLib.Harmony; +using UnityEngine.Scripting; +using TypeAttributes = Mono.Cecil.TypeAttributes; +using MethodAttributes = Mono.Cecil.MethodAttributes; +using FieldAttributes = Mono.Cecil.FieldAttributes; +using Mono.Cecil.Rocks; + +namespace KFCommonUtilityLib +{ + public interface IModuleContainerFor where T : class + { + T Instance { get; } + } + + public class TranspilerTarget + { + public TranspilerTarget(Type type_action, MethodInfo mtdinf_original, PatchInfo patchinf_harmony) + { + this.type_action = type_action; + this.mtdinf_original = mtdinf_original; + this.patchinf_harmony = patchinf_harmony; + } + + public Type type_action; + public MethodInfo mtdinf_original; + public PatchInfo patchinf_harmony; + } + + public class MethodPatchInfo + { + public readonly MethodDefinition Method; + public Instruction PrefixBegin; + public Instruction PostfixBegin; + public Instruction PostfixEnd; + + public MethodPatchInfo(MethodDefinition mtddef, Instruction postfixEnd, Instruction prefixBegin) + { + Method = mtddef; + PostfixEnd = postfixEnd; + PrefixBegin = prefixBegin; + } + } + + internal struct MethodOverrideInfo + { + public MethodInfo mtdinf_target; + public MethodInfo mtdinf_base; + public MethodReference mtdref_base; + public Type prefType; + + public MethodOverrideInfo(MethodInfo mtdinf_target, MethodInfo mtdinf_base, MethodReference mtddef_base, Type prefType) + { + this.mtdinf_target = mtdinf_target; + this.mtdinf_base = mtdinf_base; + this.mtdref_base = mtddef_base; + this.prefType = prefType; + } + } + + public class ModuleManipulator + { + public ModuleDefinition module; + public IModuleProcessor processor; + public Type targetType; + public Type baseType; + public Type[] moduleTypes; + public Type[][] moduleExtensionTypes; + public TypeDefinition typedef_newTarget; + public TypeReference typeref_interface; + public FieldDefinition[] arr_flddef_modules; + private static MethodInfo mtdinf = AccessTools.Method(typeof(ModuleManagers), nameof(ModuleManagers.GetModuleExtensions)); + + public ModuleManipulator(AssemblyDefinition workingAssembly, IModuleProcessor processor, Type targetType, Type baseType, params Type[] moduleTypes) + { + module = workingAssembly.MainModule; + this.processor = processor; + this.targetType = targetType; + this.baseType = baseType; + this.moduleTypes = moduleTypes; + moduleExtensionTypes = moduleTypes.Select(t => (Type[])mtdinf.MakeGenericMethod(t).Invoke(null, null)).ToArray(); + Patch(); + } + + private void Patch() + { + typeref_interface = module.ImportReference(typeof(IModuleContainerFor<>)); + //Create new override type + TypeReference typeref_target = module.ImportReference(targetType); + typedef_newTarget = new TypeDefinition(null, ModuleUtils.CreateTypeName(targetType, moduleTypes), TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | TypeAttributes.Public | TypeAttributes.Sealed, typeref_target); + typedef_newTarget.CustomAttributes.Add(new CustomAttribute(module.ImportReference(typeof(PreserveAttribute).GetConstructor(Array.Empty())))); + module.Types.Add(typedef_newTarget); + + //Create fields + arr_flddef_modules = new FieldDefinition[moduleTypes.Length]; + for (int i = 0; i < moduleTypes.Length; i++) + { + //Create ItemAction field + Type type_module = moduleTypes[i]; + MakeContainerFor(typedef_newTarget, type_module, out var flddef_module); + arr_flddef_modules[i] = flddef_module; + } + + //Create ItemAction constructor + MethodDefinition mtddef_ctor = new MethodDefinition(".ctor", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, module.TypeSystem.Void); + if (processor == null || !processor.BuildConstructor(this, mtddef_ctor)) + { + var il = mtddef_ctor.Body.GetILProcessor(); + il.Append(il.Create(OpCodes.Ldarg_0)); + il.Append(il.Create(OpCodes.Call, module.ImportReference(targetType.GetConstructor(Array.Empty())))); + il.Append(il.Create(OpCodes.Nop)); + for (int i = 0; i < arr_flddef_modules.Length; i++) + { + il.Append(il.Create(OpCodes.Ldarg_0)); + il.Append(il.Create(OpCodes.Newobj, module.ImportReference(moduleTypes[i].GetConstructor(Array.Empty())))); + il.Append(il.Create(OpCodes.Stfld, arr_flddef_modules[i])); + il.Append(il.Create(OpCodes.Nop)); + } + il.Append(il.Create(OpCodes.Ret)); + } + typedef_newTarget.Methods.Add(mtddef_ctor); + + processor?.InitModules(this, targetType, baseType, moduleTypes); + + // + Dictionary dict_overrides = new Dictionary(); + // + //TODO: USE TREE INSTEAD OF LIST + Dictionary> dict_transpilers = new Dictionary>(); + //> + Dictionary> dict_all_states = new Dictionary>(); + + //Get all transpilers + for (int i = 0; i < moduleTypes.Length; i++) + { + Type moduleType = moduleTypes[i]; + const BindingFlags searchFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; + foreach (var mtd in moduleType.GetMethods(searchFlags).Concat(moduleExtensionTypes[i].SelectMany(t => t.GetMethods(searchFlags)))) + { + var attr = mtd.GetCustomAttribute(); + foreach (var hp in mtd.GetCustomAttributes()) + { + //make sure the transpiler has a target method to apply, otherwise skip it + if (attr != null && hp != null && hp.info.declaringType != null) + { + var hm = hp.info; + hm.methodType = hm.methodType ?? MethodType.Normal; + var mtdinf_target = hm.GetOriginalMethod() as MethodInfo; + if (mtdinf_target == null || mtdinf_target.IsAbstract || !mtdinf_target.IsVirtual) + { + continue; + } + string id = hm.GetTargetMethodIdentifier(); + if (!dict_transpilers.TryGetValue(id, out var list)) + { + dict_transpilers[id] = (list = new List()); + Type nextType = targetType; + TranspilerTarget curNode = null; + var hm_next = hm.Clone(); + while (hm.declaringType.IsAssignableFrom(nextType)) + { + hm_next.declaringType = nextType; + var mtdinfo_cur = hm_next.GetOriginalMethod() as MethodInfo; + if (mtdinfo_cur != null) + { + var patchinf_harmony = mtdinfo_cur.ToPatchInfoDontAdd().Copy(); + curNode = new TranspilerTarget(mtdinfo_cur.DeclaringType, mtdinfo_cur, patchinf_harmony); + list.Add(curNode); + } + nextType = nextType.BaseType; + } + + if (curNode != null) + { + curNode.patchinf_harmony.AddTranspilers(CommonUtilityLibInit.HarmonyInstance.Id, new HarmonyMethod(mtd)); + Log.Out($"Adding transpiler {mtd.FullDescription()}\nCurrent transpilers:\n{string.Join('\n', curNode.patchinf_harmony.transpilers.Select(p => p.PatchMethod.FullDescription()))}"); + } + } + else + { + bool childFound = false; + foreach (var node in ((IEnumerable)list).Reverse()) + { + if (node.type_action.Equals(hm.declaringType)) + { + childFound = true; + node.patchinf_harmony.AddTranspilers(CommonUtilityLibInit.HarmonyInstance.Id, mtd); + Log.Out($"Adding transpiler {mtd.FullDescription()}\nCurrent transpilers:\n{string.Join('\n', node.patchinf_harmony.transpilers.Select(p => p.PatchMethod.FullDescription()))}"); + break; + } + } + + if (!childFound) + { + Type nextType = list[list.Count - 1].type_action.BaseType; + TranspilerTarget curNode = null; + var hm_next = hm.Clone(); + while (hm.declaringType.IsAssignableFrom(nextType)) + { + hm_next.declaringType = nextType; + var mtdinfo_cur = hm_next.GetOriginalMethod() as MethodInfo; + if (mtdinfo_cur != null) + { + var patchinf_harmony = mtdinfo_cur.ToPatchInfoDontAdd().Copy(); + curNode = new TranspilerTarget(mtdinfo_cur.DeclaringType, mtdinfo_cur, patchinf_harmony); + list.Add(curNode); + } + nextType = nextType.BaseType; + } + + if (curNode != null) + { + curNode.patchinf_harmony.AddTranspilers(CommonUtilityLibInit.HarmonyInstance.Id, new HarmonyMethod(mtd)); + Log.Out($"Adding transpiler {mtd.FullDescription()}\nCurrent transpilers:\n{string.Join('\n', curNode.patchinf_harmony.transpilers.Select(p => p.PatchMethod.FullDescription()))}"); + } + } + } + } + } + } + } + + //apply transpilers and replace method calls on base methods with patched ones + Dictionary dict_replacers = new Dictionary(); + foreach (var pair in dict_transpilers) + { + List list = pair.Value; + + //the top copy to call in the override method + MethodDefinition mtddef_override_copy = null; + MethodReference mtdref_override_base = null; + for (int i = list.Count - 1; i >= 0; i--) + { + TranspilerTarget curNode = list[i]; + MethodPatcher patcher = curNode.mtdinf_original.GetMethodPatcher(); + DynamicMethodDefinition dmd = patcher.CopyOriginal(); + ILContext context = new ILContext(dmd.Definition); + HarmonyManipulator.Manipulate(curNode.mtdinf_original, curNode.patchinf_harmony, context); + var mtdref_original = module.ImportReference(curNode.mtdinf_original); + var mtddef_copy = mtdref_original.Resolve().CloneToModuleAsStatic(context.Body, module.ImportReference(curNode.type_action), module); + dmd.Dispose(); + context.Dispose(); + if (mtddef_override_copy != null && mtdref_override_base != null) + { + //replace calls to the base + foreach (var ins in mtddef_copy.Body.Instructions) + { + if (ins.OpCode == OpCodes.Call && ((MethodReference)ins.Operand).FullName.Equals(mtdref_override_base.FullName)) + { + Log.Out($"replacing call to {mtdref_override_base.FullName} to {mtddef_override_copy.FullName}"); + ins.Operand = mtddef_override_copy; + } + } + } + //add patched copy to the class + typedef_newTarget.Methods.Add(mtddef_copy); + //the iteration is reversed so make sure we grab the latest method + mtddef_override_copy = mtddef_copy; + mtdref_override_base = mtdref_original; + } + //create the method override that calls the patched copy + if (mtddef_override_copy != null && mtdref_override_base != null) + { + GetOrCreateOverride(dict_overrides, pair.Key, mtdref_override_base, mtddef_override_copy); + } + } + + //Apply Postfixes first so that Prefixes can jump to the right instruction + for (int i = 0; i < moduleTypes.Length; i++) + { + Type moduleType = moduleTypes[i]; + Dictionary dict_targets = GetMethodOverrideTargets(i); + string moduleID = ModuleUtils.CreateFieldName(moduleType); + foreach (var pair in dict_targets) + { + MethodDefinition mtddef_root = module.ImportReference(pair.Value.mtdinf_base.GetBaseDefinition()).Resolve(); + MethodDefinition mtddef_target = module.ImportReference(pair.Value.mtdinf_target).Resolve(); + MethodPatchInfo mtdpinf_derived = GetOrCreateOverride(dict_overrides, pair.Key, pair.Value.mtdref_base); + MethodDefinition mtddef_derived = mtdpinf_derived.Method; + + if (!dict_all_states.TryGetValue(pair.Key, out var dict_states)) + { + dict_states = new Dictionary(); + dict_all_states.Add(pair.Key, dict_states); + } + var list_inst_pars = MatchArguments(mtddef_root, mtdpinf_derived, mtddef_target, i, true, dict_states, moduleID); + //insert invocation + var il = mtddef_derived.Body.GetILProcessor(); + foreach (var ins in list_inst_pars) + { + il.InsertBefore(mtdpinf_derived.PostfixEnd, ins); + } + il.InsertBefore(mtdpinf_derived.PostfixEnd, il.Create(OpCodes.Call, module.ImportReference(mtddef_target))); + if (mtdpinf_derived.PostfixBegin == null) + mtdpinf_derived.PostfixBegin = list_inst_pars[0]; + } + } + + //Apply Prefixes + for (int i = moduleTypes.Length - 1; i >= 0; i--) + { + Type moduleType = moduleTypes[i]; + Dictionary dict_targets = GetMethodOverrideTargets(i); + string moduleID = ModuleUtils.CreateFieldName(moduleType); + foreach (var pair in dict_targets) + { + MethodDefinition mtddef_root = module.ImportReference(pair.Value.mtdinf_base.GetBaseDefinition()).Resolve(); + MethodDefinition mtddef_target = module.ImportReference(pair.Value.mtdinf_target).Resolve(); + MethodPatchInfo mtdpinf_derived = GetOrCreateOverride(dict_overrides, pair.Key, pair.Value.mtdref_base); + MethodDefinition mtddef_derived = mtdpinf_derived.Method; + dict_all_states.TryGetValue(pair.Key, out var dict_states); + var list_inst_pars = MatchArguments(mtddef_root, mtdpinf_derived, mtddef_target, i, false, dict_states, moduleID); + //insert invocation + var il = mtdpinf_derived.Method.Body.GetILProcessor(); + Instruction ins_insert = mtdpinf_derived.PrefixBegin; + foreach (var ins in list_inst_pars) + { + il.InsertBefore(ins_insert, ins); + } + il.InsertBefore(ins_insert, il.Create(OpCodes.Call, module.ImportReference(mtddef_target))); + il.InsertBefore(ins_insert, il.Create(OpCodes.Brfalse_S, mtdpinf_derived.PostfixBegin ?? mtdpinf_derived.PostfixEnd)); + } + } + + foreach (var pair in dict_all_states) + { + var dict_states = pair.Value; + if (dict_states.Count > 0) + { + Log.Error($"__state variable count does not match in prefixes and postfixes for {pair.Key}! check following modules:\n" + string.Join("\n", dict_states.Keys)); + throw new Exception(); + } + } + + //Add all overrides to new type + foreach (var mtd in dict_overrides.Values) + { + typedef_newTarget.Methods.Add(mtd.Method); + + //Log.Out($"Add method override to new action: {mtd.Method.Name}"); + } + } + + /// + /// + /// + /// + /// + /// + /// + /// + private Dictionary GetMethodOverrideTargets(int moduleIndex) where T : Attribute, IMethodTarget + { + Type moduleType = moduleTypes[moduleIndex]; + Dictionary dict_overrides = new Dictionary(); + const BindingFlags searchFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; + const BindingFlags extensionFlags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; + foreach (var mtd in moduleType.GetMethods(searchFlags).Concat(moduleExtensionTypes[moduleIndex].SelectMany(t => t.GetMethods(extensionFlags)))) + { + if (mtd.GetCustomAttribute() != null) + { + foreach (HarmonyPatch hp in mtd.GetCustomAttributes()) + { + if (hp != null && (hp.info.declaringType == null || hp.info.declaringType.IsAssignableFrom(targetType))) + { + var hm = hp.info; + hm.methodType = hm.methodType ?? MethodType.Normal; + var hmclone = hm.Clone(); + hmclone.declaringType = targetType; + string id = hm.GetTargetMethodIdentifier(); + MethodInfo mtdinf_base = hmclone.GetBaseMethod() as MethodInfo; + if (mtdinf_base == null || !mtdinf_base.IsVirtual || mtdinf_base.IsFinal) + { + Log.Error($"Method not found: {moduleType.FullName} on {hmclone.methodName}\n{hmclone.ToString()}"); + continue; + } + + MethodReference mtdref_base = module.ImportReference(mtdinf_base); + //Find preferred patch + if (dict_overrides.TryGetValue(id, out var info)) + { + if (hm.declaringType == null) + continue; + //cur action type is sub or same class of cur preferred type + //cur preferred type is sub class of previous preferred type + //means cur preferred type is closer to the action type in inheritance hierachy than the previous one + if (hm.declaringType.IsAssignableFrom(targetType) && (info.prefType == null || hm.declaringType.IsSubclassOf(info.prefType))) + { + dict_overrides[id] = new MethodOverrideInfo(mtd, mtdinf_base, mtdref_base, hm.declaringType); + } + } + else + { + dict_overrides[id] = new MethodOverrideInfo(mtd, mtdinf_base, mtdref_base, hm.declaringType); + } + //Log.Out($"Add method override: {id} for {mtdref_base.FullName}/{mtdinf_base.Name}, action type: {itemActionType.Name}"); + } + else + { + //Log.Out($"No override target found or preferred type not match on {mtd.Name}"); + } + } + } + } + return dict_overrides; + } + + /// + /// Get or create override MethodDefinition of mtdref_base. + /// + /// + /// + /// + /// + /// + private MethodPatchInfo GetOrCreateOverride(Dictionary dict_overrides, string id, MethodReference mtdref_base, MethodDefinition mtddef_base_override = null) + { + //if (mtddef_base.FullName == "CreateModifierData") + // throw new MethodAccessException($"YOU SHOULD NOT MANUALLY MODIFY CreateModifierData!"); + if (dict_overrides.TryGetValue(id, out var mtdpinf_derived)) + { + return mtdpinf_derived; + } + //when overriding, retain attributes of base but make sure to remove the 'new' keyword which presents if you are overriding the root method + MethodDefinition mtddef_base = mtdref_base.Resolve(); + MethodDefinition mtddef_derived = new MethodDefinition(mtddef_base.Name, (mtddef_base.Attributes | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.ReuseSlot) & ~MethodAttributes.NewSlot, module.ImportReference(mtddef_base.ReturnType)); + + //Log.Out($"Create method override: {id} for {mtdref_base.FullName}"); + foreach (var par in mtddef_base_override?.Parameters?.Skip(1) ?? mtddef_base.Parameters) + { + ParameterDefinition pardef = new ParameterDefinition(par.Name, par.Attributes, module.ImportReference(par.ParameterType)); + if (par.HasConstant) + pardef.Constant = par.Constant; + mtddef_derived.Parameters.Add(pardef); + } + mtddef_derived.Body.Variables.Clear(); + mtddef_derived.Body.InitLocals = true; + mtddef_derived.Body.Variables.Add(new VariableDefinition(module.TypeSystem.Boolean)); + bool hasReturnVal = mtddef_derived.ReturnType.MetadataType != MetadataType.Void; + if (hasReturnVal) + { + mtddef_derived.Body.Variables.Add(new VariableDefinition(module.ImportReference(mtddef_base.ReturnType))); + } + var il = mtddef_derived.Body.GetILProcessor(); + if (hasReturnVal) + { + il.Emit(OpCodes.Ldloca_S, mtddef_derived.Body.Variables[1]); + il.Emit(OpCodes.Initobj, module.ImportReference(mtddef_derived.ReturnType)); + } + il.Emit(OpCodes.Ldc_I4_0); + il.Emit(OpCodes.Stloc_S, mtddef_derived.Body.Variables[0]); + Instruction prefixBegin = il.Create(OpCodes.Ldc_I4_1); + il.Append(prefixBegin); + il.Emit(OpCodes.Stloc_S, mtddef_derived.Body.Variables[0]); + il.Emit(OpCodes.Ldarg_0); + for (int i = 0; i < mtddef_derived.Parameters.Count; i++) + { + var par = mtddef_derived.Parameters[i]; + il.Emit(par.ParameterType.IsByReference ? OpCodes.Ldarga_S : OpCodes.Ldarg_S, par); + } + il.Emit(OpCodes.Call, mtddef_base_override ?? module.ImportReference(mtdref_base)); + if (hasReturnVal) + { + il.Emit(OpCodes.Stloc_S, mtddef_derived.Body.Variables[1]); + il.Emit(OpCodes.Ldloc_S, mtddef_derived.Body.Variables[1]); + } + il.Emit(OpCodes.Ret); + mtdpinf_derived = new MethodPatchInfo(mtddef_derived, mtddef_derived.Body.Instructions[mtddef_derived.Body.Instructions.Count - (hasReturnVal ? 2 : 1)], prefixBegin); + dict_overrides.Add(id, mtdpinf_derived); + return mtdpinf_derived; + } + + /// + /// Create a List that loads all arguments required to call the method onto stack. + /// + /// The root definition of this method. + /// The override method. + /// The patch method to be called. + /// The injected module field. + /// The injected data field. + /// The assembly's main module. + /// The base ItemAction type. + /// + /// + /// + /// + private List MatchArguments(MethodDefinition mtddef_root, MethodPatchInfo mtdpinf_derived, MethodDefinition mtddef_target, int moduleIndex, bool isPostfix, Dictionary dict_states, string moduleID) + { + FieldDefinition flddef_module = arr_flddef_modules[moduleIndex]; + var mtddef_derived = mtdpinf_derived.Method; + var il = mtddef_derived.Body.GetILProcessor(); + //Match parameters + List list_inst_pars = new List(); + list_inst_pars.Add(il.Create(OpCodes.Ldarg_0)); + list_inst_pars.Add(il.Create(OpCodes.Ldfld, flddef_module)); + foreach (var par in mtddef_target.IsStatic ? mtddef_target.Parameters.Skip(1) : mtddef_target.Parameters) + { + if (par.Name.StartsWith("___")) + { + //___ means non public fields + string str_fldname = par.Name.Substring(3); + FieldDefinition flddef_target = module.ImportReference(targetType.GetField(str_fldname, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)).Resolve(); + if (flddef_target == null) + throw new MissingFieldException($"Field with name \"{str_fldname}\" not found! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + if (flddef_target.IsStatic) + { + list_inst_pars.Add(il.Create((par.ParameterType.IsByReference) ? OpCodes.Ldsflda : OpCodes.Ldsfld, module.ImportReference(flddef_target))); + } + else + { + list_inst_pars.Add(il.Create(OpCodes.Ldarg_0)); + list_inst_pars.Add(il.Create(par.ParameterType.IsByReference ? OpCodes.Ldflda : OpCodes.Ldfld, module.ImportReference(flddef_target))); + } + } + else if (!MatchSpecialParameters(par, mtddef_target, mtdpinf_derived, moduleIndex, list_inst_pars, il, isPostfix, dict_states, moduleID)) + { + //match param by name + int index = -1; + for (int j = 0; j < mtddef_root.Parameters.Count; j++) + { + if (mtddef_root.Parameters[j].Name == par.Name) + { + index = mtddef_root.Parameters[j].Index; + break; + } + } + if (index < 0) + throw new ArgumentException($"Parameter \"{par.Name}\" not found! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + try + { + //Log.Out($"Match Parameter {par.Name} to {mtddef_derived.Parameters[index].Name}/{mtddef_root.Parameters[index].Name} index: {index}"); + + } + catch (ArgumentOutOfRangeException e) + { + Log.Error($"index {index} parameter {par.Name}" + + $"root pars: {{{string.Join(",", mtddef_root.Parameters.Select(p => p.Name + "/" + p.Index).ToArray())}}}" + + $"derived pars: {{{string.Join(",", mtddef_derived.Parameters.Select(p => p.Name + "/" + p.Index).ToArray())}}}"); + throw e; + } + if (!mtddef_derived.Parameters[index].ParameterType.IsByReference) + { + list_inst_pars.Add(il.Create(par.ParameterType.IsByReference ? OpCodes.Ldarga_S : OpCodes.Ldarg_S, mtddef_derived.Parameters[index])); + } + else + { + list_inst_pars.Add(il.Create(OpCodes.Ldarg_S, mtddef_derived.Parameters[index])); + if (!par.ParameterType.IsByReference) + { + list_inst_pars.Add(il.Create(OpCodes.Ldind_Ref)); + } + } + } + } + return list_inst_pars; + } + + private bool MatchSpecialParameters(ParameterDefinition par, MethodDefinition mtddef_target, MethodPatchInfo mtdpinf_derived, int moduleIndex, List list_inst_pars, ILProcessor il, bool isPostfix, Dictionary dict_states, string moduleID) + { + MethodDefinition mtddef_derived = mtdpinf_derived.Method; + switch (par.Name) + { + //load ItemAction instance + case "__instance": + list_inst_pars.Add(il.Create(OpCodes.Ldarg_0)); + break; + //load return value + case "__result": + list_inst_pars.Add(il.Create(par.ParameterType.IsByReference ? OpCodes.Ldloca_S : OpCodes.Ldloc_S, mtddef_derived.Body.Variables[1])); + break; + //for postfix only, indicates whether original method is executed + case "__runOriginal": + if (par.ParameterType.IsByReference) + throw new ArgumentException($"__runOriginal is readonly! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + list_inst_pars.Add(il.Create(OpCodes.Ldloc_S, mtddef_derived.Body.Variables[0])); + break; + case "__state": + if (dict_states == null) + { + throw new ArgumentNullException($"__state is found in prefix but no matching postfix exists! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + } + if (!isPostfix && !dict_states.TryGetValue(moduleID, out var vardef)) + { + throw new KeyNotFoundException($"__state is found in prefix but not found in corresponding postfix! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + } + if (par.IsOut && isPostfix) + { + throw new ArgumentException($"__state is marked as out parameter in postfix! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + } + if (!par.IsOut && !isPostfix) + { + throw new ArgumentException($"__state is not marked as out in prefix! Patch method: {mtddef_target.DeclaringType.FullName}.{mtddef_target.Name}"); + } + if (isPostfix) + { + vardef = new VariableDefinition(module.ImportReference(par.ParameterType)); + mtddef_derived.Body.Variables.Add(vardef); + dict_states.Add(moduleID, vardef); + var ins = mtddef_derived.Body.Instructions[0]; + il.InsertBefore(ins, il.Create(OpCodes.Ldloca_S, vardef)); + il.InsertBefore(ins, il.Create(OpCodes.Initobj, module.ImportReference(par.ParameterType))); + list_inst_pars.Add(il.Create(OpCodes.Ldloc_S, vardef)); + } + else + { + vardef = dict_states[moduleID]; + dict_states.Remove(moduleID); + list_inst_pars.Add(il.Create(OpCodes.Ldloca_S, vardef)); + } + break; + default: + return processor != null ? processor.MatchSpecialArgs(par, mtddef_target, mtdpinf_derived, moduleIndex, list_inst_pars, il) : false; + } + return true; + } + + public void MakeContainerFor(TypeDefinition typedef_container, Type type_module, out FieldDefinition flddef_module) + { + var typeref_module = module.ImportReference(type_module); + flddef_module = new FieldDefinition(ModuleUtils.CreateFieldName(type_module), FieldAttributes.Public, typeref_module); + typedef_container.Fields.Add(flddef_module); + typedef_container.Interfaces.Add(new InterfaceImplementation(typeref_interface.MakeGenericInstanceType(typeref_module))); + PropertyDefinition propdef_instance = new PropertyDefinition("Instance", Mono.Cecil.PropertyAttributes.None, typeref_module); + MethodDefinition mtddef_instance_getter = new MethodDefinition("get_Instance", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final, typeref_module); + mtddef_instance_getter.Overrides.Add(module.ImportReference(AccessTools.Method(typeof(IModuleContainerFor<>).MakeGenericType(type_module), "get_Instance"))); + typedef_container.Methods.Add(mtddef_instance_getter); + mtddef_instance_getter.Body = new Mono.Cecil.Cil.MethodBody(mtddef_instance_getter); + var generator = mtddef_instance_getter.Body.GetILProcessor(); + generator.Emit(OpCodes.Ldarg_0); + generator.Emit(OpCodes.Ldfld, flddef_module); + generator.Emit(OpCodes.Ret); + propdef_instance.GetMethod = mtddef_instance_getter; + typedef_container.Properties.Add(propdef_instance); + } + } +} diff --git a/Scripts/Utilities/Modular/ModuleUtils.cs b/Scripts/Utilities/Modular/ModuleUtils.cs new file mode 100644 index 0000000..bd2f9db --- /dev/null +++ b/Scripts/Utilities/Modular/ModuleUtils.cs @@ -0,0 +1,67 @@ +using HarmonyLib; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Cecil.Rocks; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace KFCommonUtilityLib +{ + public static class ModuleUtils + { + public static string CreateFieldName(Type moduleType) + { + return (moduleType.FullName + "_" + moduleType.Assembly.GetName().Name).ReplaceInvalidChar(); + } + + public static string CreateFieldName(TypeReference moduleType) + { + return (moduleType.FullName + "_" + moduleType.Module.Assembly.Name.Name).ReplaceInvalidChar(); + } + + public static string CreateTypeName(Type itemActionType, params Type[] moduleTypes) + { + string typeName = itemActionType.FullName + "_" + itemActionType.Assembly.GetName().Name; + foreach (Type type in moduleTypes) + { + if (type != null) + typeName += "__" + type.FullName + "_" + type.Assembly.GetName().Name; + } + typeName = typeName.ReplaceInvalidChar(); + return typeName; + } + + public static string CreateTypeName(TypeReference itemActionType, params TypeReference[] moduleTypes) + { + string typeName = itemActionType.FullName + "_" + itemActionType.Module.Assembly.Name.Name; + foreach (TypeReference type in moduleTypes) + { + if (type != null) + typeName += "__" + type.FullName + "_" + type.Module.Assembly.Name.Name; + } + typeName = typeName.ReplaceInvalidChar(); + return typeName; + } + + private static string ReplaceInvalidChar(this string self) + { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < self.Length; i++) + { + char c = self[i]; + if (!char.IsLetterOrDigit(c) && c != '_') + { + sb.Append('_'); + } + else + { + sb.Append(c); + } + } + return sb.ToString(); + } + } +} diff --git a/Scripts/Utilities/MonoCecilExtensions.cs b/Scripts/Utilities/MonoCecilExtensions.cs new file mode 100644 index 0000000..34d83fb --- /dev/null +++ b/Scripts/Utilities/MonoCecilExtensions.cs @@ -0,0 +1,1685 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using Mono.Cecil; +using Mono.Cecil.Cil; +using Mono.Collections.Generic; +using MethodBody = Mono.Cecil.Cil.MethodBody; + +/// +/// https://github.com/snaphat/MonoCecilExtensions +/// Provides extension methods for classes from the Mono.Cecil library, a library for reading and writing Intermediate Language (IL) code. +/// These extensions facilitate manipulation of IL code, providing functionality to clone, merge, and update types in collections, methods, fields, and other components of a .NET assembly. +/// +public static class MonoCecilExtensions +{ + /// + /// Represents an information container for updating Mono.Cecil definitions. + /// + public class UpdateInfo + { + /// + /// A collection of CustomAttribute objects that have been updated. + /// + public readonly Collection updatedAttributes = new Collection(); + + /// + /// A collection of InterfaceImplementation objects that have been updated. + /// + public readonly Collection updatedInterfaces = new Collection(); + + /// + /// A collection of FieldDefinition objects that have been updated. + /// + public readonly Collection updatedFields = new Collection(); + + /// + /// A collection of PropertyDefinition objects that have been updated. + /// + public readonly Collection updatedProperties = new Collection(); + + /// + /// A collection of MethodDefinition objects that have been updated. + /// + public readonly Collection updatedMethods = new Collection(); + + /// + /// A collection of source TypeDefinition objects that are being merged. + /// + public readonly Collection srcTypes = new Collection(); + + /// + /// A collection of destination TypeDefinition objects where source objects are merged into. + /// + public readonly Collection destTypes = new Collection(); + }; + + /// + /// A dictionary mapping from AssemblyDefinition objects to their corresponding UpdateInfo objects. + /// Used to keep track of the updates made to each assembly. + /// + public static readonly Dictionary assemblyUpdateInfo = new Dictionary (); + + /// + /// Additional search directories for resolving assembly types. + /// + public static readonly Collection additionalSearchDirectories = new Collection(); + + // Basic extension methods for loading assemblies, adding elements to collections, and finding types, fields, and methods in Mono.Cecil objects. + #region Base + + /// + /// This extension method loads an assembly from a given location. + /// + /// The location of the assembly to be loaded. + /// A boolean value to determine if the assembly is read-only or writable. + /// The AssemblyDefinition object of the loaded assembly if successful + public static AssemblyDefinition LoadAssembly(this string location, bool readWrite = false) + { + // Create a new instance of the DefaultAssemblyResolver. + var resolver = new DefaultAssemblyResolver(); + + // Add search directories to the resolver. + foreach (var directory in additionalSearchDirectories) + resolver.AddSearchDirectory(directory); + resolver.AddSearchDirectory(Path.GetDirectoryName(typeof(int).Assembly.Location)); + resolver.AddSearchDirectory(Path.Combine(Path.GetDirectoryName(typeof(int).Assembly.Location), "Facades")); + + // Read and return the assembly using the provided location and reader parameters. + return AssemblyDefinition.ReadAssembly(location, new ReaderParameters() + { + AssemblyResolver = resolver, + ReadWrite = readWrite, + }); + } + + /// + /// This extension method finds a method of a given type in an assembly. + /// + /// The assembly where the type and method are located. + /// The full or simple name of the type. + /// The full or simple name of the method. + /// The MethodDefinition object of the found method. Null if not found. + public static MethodDefinition FindMethodOfType(this AssemblyDefinition assembly, string typeSignature, string methodSignature) + { + // Find and return the method of the given type in the assembly. + return assembly.FindType(typeSignature)?.FindMethod(methodSignature); + } + + /// + /// This extension method finds a type in an assembly using its full name or simple name. + /// + /// The assembly where the type is located. + /// The full or simple name of the type. + /// The TypeDefinition object of the found type. Null if not found. + public static TypeDefinition FindType(this AssemblyDefinition assembly, string typeSignature) + { + // Return the first type that matches the provided type signature. + return assembly.MainModule.Types.FirstOrDefault(type => type.FullName == typeSignature || type.Name == typeSignature); + } + + /// + /// This extension method finds a type in an assembly using its full name or simple name. + /// + /// The assembly where the type is located. + /// The type to locate. + /// The TypeDefinition object of the found type. Null if not found. + public static TypeDefinition FindType(this AssemblyDefinition assembly, Type type) + { + // Return the first type that matches the provided type signature. + return assembly.MainModule.Types.FirstOrDefault(_type => _type.FullName == type.FullName || _type.Name == type.Name); + } + + /// + /// This extension method finds a field in a type. + /// + /// The type where the field is located. + /// The full or simple name of the field. + /// The FieldDefinition object of the found field. Null if not found. + public static FieldDefinition FindField(this TypeDefinition type, string fieldSignature) + { + // Return the first field that matches the provided field signature. + return type.Fields.FirstOrDefault(m => m.FullName == fieldSignature || m.Name == fieldSignature); + } + + /// + /// This extension method finds a method in a type. + /// + /// The type where the method is located. + /// The full or simple name of the method. + /// The MethodDefinition object of the found method. Null if not found. + public static MethodDefinition FindMethod(this TypeDefinition type, string methodSignature) + { + // The function checks each method in the type's Methods collection, + // and returns the first method whose full name or simple name matches the provided method signature. + return type.Methods.FirstOrDefault(m => m.FullName == methodSignature || m.Name == methodSignature); + } + + /// + /// This extension method finds all methods in a type that match a given method signature. + /// + /// The type where the methods are located. + /// The full or simple name of the methods. + /// A collection of MethodDefinition objects for the found methods. Empty collection if none found. + public static Collection FindMethods(this TypeDefinition type, string methodSignature) + { + var collection = new Collection(); + + // This function checks each method in the type's Methods collection, + // and adds those methods to the collection whose full name or simple name matches the provided method signature. + foreach (var item in type.Methods.Where(m => m.FullName == methodSignature || m.Name == methodSignature)) + collection.Add(item); + return collection; + } + + #endregion Base + + // Extension method that handles adding types to an assembly. + #region AddType + + /// + /// Adds a type to an assembly. This includes adding the type's fields, properties, and methods. + /// If the source type is nested, it will be added as a nested type within the parent type in the destination assembly. + /// + /// The assembly to which the type will be added. + /// The source type that will be added to the assembly. + /// Avoid name conflicts by adding a '_' suffix to the copied class name. + public static void AddType(this AssemblyDefinition assembly, TypeDefinition src, bool avoidSignatureConflicts = false) + { + // Check for signature conflict avoidance + var srcName = src.Name; + if (avoidSignatureConflicts) src.Name += "_"; + + // Create a new TypeDefinition with the same properties as the source type + var dest = new TypeDefinition(src.Namespace, src.Name, src.Attributes); + + // If the source type isn't nested, add the new type directly to the assembly's types + // Otherwise, find the declaring type in the assembly and add the new type as a nested type + if (!src.IsNested) + assembly.MainModule.Types.Add(dest); + else + assembly.FindType(src.DeclaringType.FullName).NestedTypes.Add(dest); + + // Set the base type of the new type to match the base type of the source type + dest.BaseType = src.BaseType; + + // Add the fields, properties, and methods from the source type to the new type + dest.AddFieldsPropertiesAndMethods(src); + + // Restore name + if (avoidSignatureConflicts) src.Name = srcName; + } + + #endregion AddType + + // Extension method that handles the addition of fields, properties, and methods from a source type to a destination type. + // This is a key part of merging two types, ensuring the destination type includes all necessary components from the source type. + #region AddFieldsPropertiesAndMethods + + /// + /// Merges the source type into the destination type by cloning the fields, properties, and methods of the source, updating their types and adding them to the destination. + /// + /// The destination type definition where fields, properties, and methods from source will be added. + /// The source type definition whose fields, properties, and methods will be cloned and added to the destination. + public static void AddFieldsPropertiesAndMethods(this TypeDefinition dest, TypeDefinition src) + { + // Add nested types to the module + foreach (var subtype in src.NestedTypes) + dest.Module.Assembly.AddType(subtype); + + // Clone attributes from the source and add to the destination + var clonedAttributes = new Collection(); + foreach (var attribute in src.CustomAttributes) + { + var clonedAttribute = attribute.Clone(); + dest.CustomAttributes.Add(clonedAttribute); + clonedAttributes.Add(clonedAttribute); + } + + // Clone interfaces from the source and add to the destination + var clonedInterfaces = new Collection(); + foreach (var @interface in src.Interfaces) + { + var clonedInterface = @interface.Clone(); + dest.Interfaces.Add(clonedInterface); + clonedInterfaces.Add(clonedInterface); + } + + // Clone fields from the source and add to the destination + var clonedFields = new Collection(); + foreach (var field in src.Fields) + { + var clonedField = field.Clone(); + clonedFields.Add(clonedField); + dest.Fields.Add(clonedField); + } + + // Clone properties from the source and add to the destination + var clonedProperties = new Collection(); + foreach (var property in src.Properties) + { + var clonedProperty = property.Clone(); + clonedProperties.Add(clonedProperty); + dest.Properties.Add(clonedProperty); + } + + // Clone methods from the source (don't add to the destination yet) + var clonedMethods = new Collection(); + foreach (var method in src.Methods) + { + var clonedMethod = method.Clone(); + clonedMethods.Add(clonedMethod); + } + + // List for keeping track of methods that need further processing + var updatedMethods = new Collection(); + + // Process each method + foreach (var clonedMethod in clonedMethods.ToList()) + { + // Special handling for constructors + if (clonedMethod.Name is ".ctor" || clonedMethod.Name is ".cctor" || clonedMethod.Name is "Finalize") + { + // Temporarily set the declaring type of the cloned method to the destination type + // This is required to get the correct full name of the method for the FindMethod call + clonedMethod.DeclaringType = dest; + + // Find an existing method in the destination type that matches the full name of the cloned method + // Note that the full name of a method includes the name of its declaring type + var destMethod = dest.FindMethod(clonedMethod.FullName); + + // Reset the declaring type of the cloned method to null + // This is done because the cloned method hasn't been added to the destination type yet, + // and leaving the declaring type set will cause failures to add the method to the destination type + clonedMethod.DeclaringType = null; + + // If destination already contains a constructor/destructor, merge the instructions + if (destMethod != null) + { + var clonedInstructions = clonedMethod.Body.Instructions; + var trimmedClonedInstructions = clonedInstructions.ToList(); + + // For constructors + if (clonedMethod.Name is ".ctor") + { + // Find the constructor call instruction and remove the instructions before it + // This is done to prevent calling the base class constructor twice when merging + var callIndex = trimmedClonedInstructions.FindIndex(x => x.OpCode == OpCodes.Call); + + // Check if callIndex is within valid range + if (callIndex < 0 || callIndex >= trimmedClonedInstructions.Count) + throw new Exception("Invalid Call Instruction Index in cloned method."); + + // Remove starting instructions + trimmedClonedInstructions.RemoveRange(0, callIndex + 1); + trimmedClonedInstructions.RemoveAt(trimmedClonedInstructions.Count - 1); + + // Insert the trimmed instructions to the existing constructor, just before the last instruction (ret) + int insertIndex = destMethod.Body.Instructions.Count - 1; + foreach (var clonedInstruction in trimmedClonedInstructions) + { + destMethod.Body.Instructions.Insert(insertIndex, clonedInstruction); + insertIndex++; + } + } + // For static constructors + else if (clonedMethod.Name is ".cctor") + { + // Remove the last instruction (ret) + trimmedClonedInstructions.RemoveAt(trimmedClonedInstructions.Count - 1); + + // Insert the trimmed instructions to the existing static constructor, just before the last instruction (ret) + int insertIndex = destMethod.Body.Instructions.Count - 1; + foreach (var clonedInstruction in trimmedClonedInstructions) + { + destMethod.Body.Instructions.Insert(insertIndex, clonedInstruction); + insertIndex++; + } + } + // For destructors + else if (clonedMethod.Name is "Finalize") + { + // Find the leave.s instruction and remove the instructions after it. + // This is done to prevent calling the base class destructor twice when merging. + var trimIndex = trimmedClonedInstructions.FindIndex(x => x.OpCode == OpCodes.Leave_S); + + // Check if trimIndex is within valid range + if (trimIndex < 0 || trimIndex >= trimmedClonedInstructions.Count) + throw new Exception("Invalid trim index in cloned method."); + + // Remove instructions after leave.s (inclusive) + trimmedClonedInstructions.RemoveRange(trimIndex, trimmedClonedInstructions.Count - trimIndex); + + // Insert the trimmed instructions to the existing destructor, at the beginning + int insertionIndex = 0; + foreach (var clonedInstruction in trimmedClonedInstructions) + { + destMethod.Body.Instructions.Insert(insertionIndex, clonedInstruction); + insertionIndex++; + } + } + + // Remove the cloned constructor or destructor from the list of methods to add to the destination type + _ = clonedMethods.Remove(clonedMethod); + + // Add the method to the list of methods to update since it has been modified + updatedMethods.Add(destMethod); + } + else + { + // Add the cloned constructor to the destination type + updatedMethods.Add(clonedMethod); + } + } + else + { + // For non-constructor/non-destructor methods + updatedMethods.Add(clonedMethod); + } + } + + // Add updated methods to the destination type + foreach (var method in clonedMethods) dest.Methods.Add(method); + + // Add updated attributes, interfaces, fields, properties and methods to the update info + if (!assemblyUpdateInfo.TryGetValue(dest.Module.Assembly, out var updateInfo)) + updateInfo = assemblyUpdateInfo[dest.Module.Assembly] = new UpdateInfo(); + foreach (var attribute in clonedAttributes) updateInfo.updatedAttributes.Add(attribute); + foreach (var @interface in clonedInterfaces) updateInfo.updatedInterfaces.Add(@interface); + foreach (var field in clonedFields) updateInfo.updatedFields.Add(field); + foreach (var property in clonedProperties) updateInfo.updatedProperties.Add(property); + foreach (var method in updatedMethods) updateInfo.updatedMethods.Add(method); + + // Add source and destination types to the update info + updateInfo.srcTypes.Add(src); + updateInfo.destTypes.Add(dest); + } + + #endregion AddFieldsPropertiesAndMethods + + // Extension methods that handle the updating of fields, properties, and methods within a destination type after they have been cloned from a source type. + // These methods ensure that the newly added components in the destination type correctly reference the destination type, rather than the original source type. + #region UpdateFieldsPropertiesAndMethods + + /// + /// Updates the types of attributes, interfaces, fields, properties, and methods within a given assembly. + /// This includes updating the types in interfaces, fields, properties, and methods. It also updates the getter and setter methods for properties, + /// updates the instruction types for methods, imports references for attributes, interfaces, fields, properties, and methods, + /// imports base types of each destination type, and swaps any duplicate methods in the destination types. + /// + /// The assembly to be updated. This assembly's types are matched against the source types and replaced with the corresponding destination types, based on previously registered update information. + /// Avoid signature conflicts by changing original method parameters to be base object types for duplicate methods + public static void UpdateFieldsPropertiesAndMethods(this AssemblyDefinition assembly, bool avoidSignatureConflicts = false) + { + // Check if update information exists for the assembly + if (assemblyUpdateInfo.TryGetValue(assembly, out var updateInfo)) + { + // Update types in interfaces, fields, properties, and methods + for (int i = 0; i < updateInfo.destTypes.Count; ++i) + foreach (var @interface in updateInfo.updatedInterfaces) @interface.UpdateTypes(updateInfo.srcTypes[i], updateInfo.destTypes[i]); + for (int i = 0; i < updateInfo.destTypes.Count; ++i) + foreach (var field in updateInfo.updatedFields) field.UpdateTypes(updateInfo.srcTypes[i], updateInfo.destTypes[i]); + for (int i = 0; i < updateInfo.destTypes.Count; ++i) + foreach (var property in updateInfo.updatedProperties) property.UpdateTypes(updateInfo.srcTypes[i], updateInfo.destTypes[i]); + for (int i = 0; i < updateInfo.destTypes.Count; ++i) + foreach (var method in updateInfo.updatedMethods) method.UpdateTypes(updateInfo.srcTypes[i], updateInfo.destTypes[i]); + + // Update getter and setter methods for properties + for (int i = 0; i < updateInfo.destTypes.Count; ++i) + foreach (var property in updateInfo.updatedProperties) property.UpdateGettersAndSetters(updateInfo.srcTypes[i], updateInfo.destTypes[i]); + + // Update instruction types for methods + for (int i = 0; i < updateInfo.destTypes.Count; ++i) + foreach (var method in updateInfo.updatedMethods) method.UpdateInstructionTypes(updateInfo.srcTypes[i], updateInfo.destTypes[i]); + + // Check for optimization opportunities for methods + foreach (var method in updateInfo.updatedMethods) method.OptimizeInstructions(); + + // Import references for attributes, interfaces, fields, properties, and methods + foreach (var attribute in updateInfo.updatedAttributes) attribute.ImportReferences(assembly.MainModule); + foreach (var @interface in updateInfo.updatedInterfaces) @interface.ImportReferences(assembly.MainModule); + foreach (var field in updateInfo.updatedFields) field.ImportReferences(assembly.MainModule); + foreach (var property in updateInfo.updatedProperties) property.ImportReferences(assembly.MainModule); + foreach (var method in updateInfo.updatedMethods) method.ImportReferences(assembly.MainModule); + + // Import base type of each dest type + foreach (var type in updateInfo.destTypes) type.BaseType = assembly.MainModule.ImportReference(type.BaseType); + + // Swap any duplicate methods in the destination types + foreach (var type in updateInfo.destTypes) type.SwapDuplicateMethods(avoidSignatureConflicts); + + // Remove the assembly from the update information collection + _ = assemblyUpdateInfo.Remove(assembly); + } + } + + #endregion UpdateFieldsPropertiesAndMethods + + // Extension methods for cloning various Mono.Cecil objects. + #region Clone + + /// + /// Clones a CustomAttribute. + /// + /// The attribute to be cloned. + /// A clone of the original attribute. + public static CustomAttribute Clone(this CustomAttribute attribute) + { + // Create a new CustomAttribute with the constructor of the original attribute. + var clonedAttribute = new CustomAttribute(attribute.Constructor); + + // Add all constructor arguments from the original attribute to the cloned attribute. + foreach (var argument in attribute.ConstructorArguments) clonedAttribute.ConstructorArguments.Add(argument); + + // Add all properties from the original attribute to the cloned attribute. + foreach (var property in attribute.Properties) clonedAttribute.Properties.Add(property); + + // Add all fields from the original attribute to the cloned attribute. + foreach (var field in attribute.Fields) clonedAttribute.Fields.Add(field); + + // Return the cloned attribute. + return clonedAttribute; + } + + /// + /// Clones a InterfaceImplementation. + /// + /// The interface to be cloned. + /// A clone of the original interface. + public static InterfaceImplementation Clone(this InterfaceImplementation @interface) + { + // Create a new InterfaceImplementation with the type the original interface. + var clonedInterface = new InterfaceImplementation(@interface.InterfaceType); + + // Copy all custom attributes from the original interface to the cloned interface. + foreach (var attribute in @interface.CustomAttributes) clonedInterface.CustomAttributes.Add(attribute.Clone()); + + // Return the cloned interface. + return clonedInterface; + } + + /// + /// Clones a FieldDefinition. + /// + /// The field to be cloned. + /// A clone of the original field. + public static FieldDefinition Clone(this FieldDefinition field) + { + // Create a new FieldDefinition with the same properties as the original field. + var clonedField = new FieldDefinition(field.Name, field.Attributes, field.FieldType); + + // Copy all custom attributes from the original field to the cloned field. + foreach (var attribute in field.CustomAttributes) clonedField.CustomAttributes.Add(attribute.Clone()); + + // Copy the MarshalInfo if it exists. + clonedField.MarshalInfo = field.MarshalInfo != null ? new MarshalInfo(field.MarshalInfo.NativeType) : null; + + // Copy the initial value of the field. + clonedField.InitialValue = field.InitialValue; + + // Return the cloned field. + return clonedField; + } + + /// + /// Clones a PropertyDefinition. + /// + /// The property to be cloned. + /// A clone of the original property. + public static PropertyDefinition Clone(this PropertyDefinition property) + { + // Create a new PropertyDefinition with the same properties as the original property. + var clonedProperty = new PropertyDefinition(property.Name, property.Attributes, property.PropertyType); + + // Copy all custom attributes from the original property to the cloned property. + foreach (var attribute in property.CustomAttributes) clonedProperty.CustomAttributes.Add(attribute.Clone()); + + // Clone the get and set methods if they exist. + clonedProperty.GetMethod = property.GetMethod?.Clone(); + clonedProperty.SetMethod = property.SetMethod?.Clone(); + + // Return the cloned property. + return clonedProperty; + } + + /// + /// Clones a ParameterDefinition. + /// + /// The parameter to be cloned. + /// A clone of the original parameter. + public static ParameterDefinition Clone(this ParameterDefinition parameter) + { + // Create a new ParameterDefinition with the same properties as the original parameter. + var clonedParameter = new ParameterDefinition(parameter.Name, parameter.Attributes, parameter.ParameterType); + + // Copy all custom attributes from the original parameter to the cloned parameter. + foreach (var attribute in parameter.CustomAttributes) clonedParameter.CustomAttributes.Add(attribute.Clone()); + + // Return the cloned parameter. + return clonedParameter; + } + + /// + /// Clones a VariableDefinition. + /// + /// The variable to be cloned. + /// A clone of the original variable. + public static VariableDefinition Clone(this VariableDefinition variable) + { + // Create and return a new VariableDefinition with the same type as the original variable. + return new VariableDefinition(variable.VariableType); + } + + /// + /// Clones an Instruction. + /// + /// The instruction to be cloned. + /// A clone of the original instruction. + public static Instruction Clone(this Instruction instruction) + { + // Create a new Instruction with a default opcode. + var clonedInstruction = Instruction.Create(OpCodes.Nop); + + // Copy the opcode and operand from the original instruction to the cloned instruction. + clonedInstruction.OpCode = instruction.OpCode; + clonedInstruction.Operand = instruction.Operand; + + // Return the cloned instruction. + return clonedInstruction; + } + + /// + /// Clones a MethodDefinition. + /// + /// The method to be cloned. + /// A clone of the original method. + public static MethodDefinition Clone(this MethodDefinition method) + { + // Create a new MethodDefinition with the same properties as the original method. + var clonedMethod = new MethodDefinition(method.Name, method.Attributes, method.ReturnType) + { + ImplAttributes = method.ImplAttributes, + SemanticsAttributes = method.SemanticsAttributes + }; + + // Add all overides from the original method to the cloned method (references). + foreach (var @override in method.Overrides) clonedMethod.Overrides.Add(@override); + + // Copy all custom attributes from the original method to the cloned method. + foreach (var attribute in method.CustomAttributes) clonedMethod.CustomAttributes.Add(attribute.Clone()); + + // Clone all parameters and add them to the cloned method. + foreach (var parameter in method.Parameters) clonedMethod.Parameters.Add(parameter.Clone()); + + // Create a new method body for the cloned method. + clonedMethod.Body = new MethodBody(clonedMethod); + + // If the original method has a body, copy the relevant properties to the cloned method's body. + if (method.HasBody) + { + clonedMethod.Body.MaxStackSize = method.Body.MaxStackSize; + clonedMethod.Body.InitLocals = method.Body.InitLocals; + + // Clone all variables and add them to the cloned method's body. + foreach (var variable in method.Body.Variables) clonedMethod.Body.Variables.Add(variable.Clone()); + + // Instruction mapping from old to new instructions used to update branch targets which is necessary after cloning + var instructionMapping = new Dictionary(); + + // Clone all the instructions and create the mapping. + foreach (var instruction in method.Body.Instructions) + { + var clonedInstruction = instruction.Clone(); + instructionMapping[instruction] = clonedInstruction; + clonedMethod.Body.Instructions.Add(clonedInstruction); + } + + // Now fix up the branch targets. + foreach (var instruction in clonedMethod.Body.Instructions) + { + // If the instruction is a branch instruction, fix up its target. + if (instruction.OpCode.FlowControl == FlowControl.Branch || + instruction.OpCode.FlowControl == FlowControl.Cond_Branch) + { + instruction.Operand = instructionMapping[(Instruction)instruction.Operand]; + } + + // If the instruction is a switch instruction, fix up its targets. + if (instruction.OpCode == OpCodes.Switch) + { + var oldTargets = (Instruction[])instruction.Operand; + var newTargets = new Instruction[oldTargets.Length]; + for (int i = 0; i < oldTargets.Length; ++i) + { + newTargets[i] = instructionMapping[oldTargets[i]]; + } + instruction.Operand = newTargets; + } + } + } + + // Return the cloned method. + return clonedMethod; + } + + public static MethodDefinition CloneToModuleAsStatic(this MethodDefinition method, TypeReference originalType, ModuleDefinition module) + { + // Create a new MethodDefinition with the same properties as the original method. + var clonedMethod = new MethodDefinition(method.Name, MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.HideBySig, module.ImportReference(method.ReturnType)) + { + ImplAttributes = method.ImplAttributes, + SemanticsAttributes = method.SemanticsAttributes + }; + + // Copy all custom attributes from the original method to the cloned method. + foreach (var attribute in method.CustomAttributes) + clonedMethod.CustomAttributes.Add(attribute.CloneToModule(module)); + + if (!method.Attributes.HasFlag(MethodAttributes.Static)) + clonedMethod.Parameters.Add(new ParameterDefinition("self", ParameterAttributes.None, originalType)); + // Clone all parameters and add them to the cloned method. + foreach (var parameter in method.Parameters) + clonedMethod.Parameters.Add(parameter.CloneToModule(module)); + + // Create a new method body for the cloned method. + clonedMethod.Body = new MethodBody(clonedMethod); + + // If the original method has a body, copy the relevant properties to the cloned method's body. + if (method.HasBody) + { + clonedMethod.Body.MaxStackSize = method.Body.MaxStackSize; + clonedMethod.Body.InitLocals = method.Body.InitLocals; + + // Clone all variables and add them to the cloned method's body. + foreach (var variable in method.Body.Variables) clonedMethod.Body.Variables.Add(variable.CloneToModule(module)); + + // Instruction mapping from old to new instructions used to update branch targets which is necessary after cloning + var instructionMapping = new Dictionary(); + + // Clone all the instructions and create the mapping. + foreach (var instruction in method.Body.Instructions) + { + var clonedInstruction = instruction.Clone(); + clonedInstruction.Resolve(clonedMethod, method, module); + instructionMapping[instruction] = clonedInstruction; + clonedMethod.Body.Instructions.Add(clonedInstruction); + } + + // Now fix up the branch targets. + foreach (var instruction in clonedMethod.Body.Instructions) + { + // If the instruction is a branch instruction, fix up its target. + if (instruction.OpCode.FlowControl == FlowControl.Branch || + instruction.OpCode.FlowControl == FlowControl.Cond_Branch) + { + instruction.Operand = instructionMapping[(Instruction)instruction.Operand]; + } + + // If the instruction is a switch instruction, fix up its targets. + if (instruction.OpCode == OpCodes.Switch) + { + var oldTargets = (Instruction[])instruction.Operand; + var newTargets = new Instruction[oldTargets.Length]; + for (int i = 0; i < oldTargets.Length; ++i) + { + newTargets[i] = instructionMapping[oldTargets[i]]; + } + instruction.Operand = newTargets; + } + } + + // copy the exception handler blocks + foreach (ExceptionHandler eh in method.Body.ExceptionHandlers) + { + ExceptionHandler neh = new ExceptionHandler(eh.HandlerType); + neh.CatchType = module.ImportReference(eh.CatchType); + + // we need to setup neh.Start and End; these are instructions; we need to locate it in the source by index + if (eh.TryStart != null) + { + int idx = method.Body.Instructions.IndexOf(eh.TryStart); + neh.TryStart = clonedMethod.Body.Instructions[idx]; + } + if (eh.TryEnd != null) + { + int idx = method.Body.Instructions.IndexOf(eh.TryEnd); + neh.TryEnd = clonedMethod.Body.Instructions[idx]; + } + + clonedMethod.Body.ExceptionHandlers.Add(neh); + } + } + + // Return the cloned method. + return clonedMethod; + } + + public static MethodDefinition CloneToModuleAsStatic(this MethodDefinition method, MethodBody body, TypeReference originalType, ModuleDefinition module) + { + // Create a new MethodDefinition with the same properties as the original method. + var clonedMethod = new MethodDefinition(method.Name, MethodAttributes.Static | MethodAttributes.Public | MethodAttributes.HideBySig, module.ImportReference(method.ReturnType)) + { + ImplAttributes = method.ImplAttributes, + SemanticsAttributes = method.SemanticsAttributes + }; + + // Copy all custom attributes from the original method to the cloned method. + foreach (var attribute in method.CustomAttributes) + clonedMethod.CustomAttributes.Add(attribute.CloneToModule(module)); + + if (!method.Attributes.HasFlag(MethodAttributes.Static)) + clonedMethod.Parameters.Add(new ParameterDefinition("self", ParameterAttributes.None, originalType)); + // Clone all parameters and add them to the cloned method. + foreach (var parameter in method.Parameters) + clonedMethod.Parameters.Add(parameter.CloneToModule(module)); + + // Create a new method body for the cloned method. + clonedMethod.Body = new MethodBody(clonedMethod); + + // If the original method has a body, copy the relevant properties to the cloned method's body. + clonedMethod.Body.MaxStackSize = body.MaxStackSize; + clonedMethod.Body.InitLocals = body.InitLocals; + + // Clone all variables and add them to the cloned method's body. + foreach (var variable in body.Variables) clonedMethod.Body.Variables.Add(variable.CloneToModule(module)); + + // Instruction mapping from old to new instructions used to update branch targets which is necessary after cloning + var instructionMapping = new Dictionary(); + + // Clone all the instructions and create the mapping. + foreach (var instruction in body.Instructions) + { + var clonedInstruction = instruction.Clone(); + clonedInstruction.Resolve(clonedMethod, method, module); + instructionMapping[instruction] = clonedInstruction; + clonedMethod.Body.Instructions.Add(clonedInstruction); + } + + // Now fix up the branch targets. + foreach (var instruction in clonedMethod.Body.Instructions) + { + // If the instruction is a branch instruction, fix up its target. + if (instruction.OpCode.FlowControl == FlowControl.Branch || + instruction.OpCode.FlowControl == FlowControl.Cond_Branch) + { + instruction.Operand = instructionMapping[(Instruction)instruction.Operand]; + } + + // If the instruction is a switch instruction, fix up its targets. + if (instruction.OpCode == OpCodes.Switch) + { + var oldTargets = (Instruction[])instruction.Operand; + var newTargets = new Instruction[oldTargets.Length]; + for (int i = 0; i < oldTargets.Length; ++i) + { + newTargets[i] = instructionMapping[oldTargets[i]]; + } + instruction.Operand = newTargets; + } + } + + // copy the exception handler blocks + foreach (ExceptionHandler eh in body.ExceptionHandlers) + { + ExceptionHandler neh = new ExceptionHandler(eh.HandlerType); + neh.CatchType = module.ImportReference(eh.CatchType); + + // we need to setup neh.Start and End; these are instructions; we need to locate it in the source by index + if (eh.TryStart != null) + { + int idx = body.Instructions.IndexOf(eh.TryStart); + neh.TryStart = clonedMethod.Body.Instructions[idx]; + } + if (eh.TryEnd != null) + { + int idx = body.Instructions.IndexOf(eh.TryEnd); + neh.TryEnd = clonedMethod.Body.Instructions[idx]; + } + + clonedMethod.Body.ExceptionHandlers.Add(neh); + } + + // Return the cloned method. + return clonedMethod; + } + + public static VariableDefinition CloneToModule(this VariableDefinition variable, ModuleDefinition module) + { + // Create and return a new VariableDefinition with the same type as the original variable. + return new VariableDefinition(module.ImportReference(variable.VariableType)); + } + + public static ParameterDefinition CloneToModule(this ParameterDefinition parameter, ModuleDefinition module) + { + // Create a new ParameterDefinition with the same properties as the original parameter. + var clonedParameter = new ParameterDefinition(parameter.Name, parameter.Attributes, module.ImportReference(parameter.ParameterType)); + + // Copy all custom attributes from the original parameter to the cloned parameter. + foreach (var attribute in parameter.CustomAttributes) + { + module.ImportReference(attribute.GetType()); + clonedParameter.CustomAttributes.Add(attribute.CloneToModule(module)); + } + + // Return the cloned parameter. + return clonedParameter; + } + + public static CustomAttribute CloneToModule(this CustomAttribute attribute, ModuleDefinition module) + { + // Create a new CustomAttribute with the constructor of the original attribute. + var clonedAttribute = new CustomAttribute(module.ImportReference(attribute.Constructor)); + + // Add all constructor arguments from the original attribute to the cloned attribute. + foreach (var argument in attribute.ConstructorArguments) + { + module.ImportReference(argument.Type); + if (argument.Value != null) + { + module.ImportReference(argument.Value?.GetType()); + } + clonedAttribute.ConstructorArguments.Add(argument); + } + + // Add all properties from the original attribute to the cloned attribute. + foreach (var property in attribute.Properties) + { + module.ImportReference(property.Argument.Type); + if (property.Argument.Value != null) + { + module.ImportReference(property.Argument.Value?.GetType()); + } + clonedAttribute.Properties.Add(property); + } + // Add all fields from the original attribute to the cloned attribute. + foreach (var field in attribute.Fields) + { + module.ImportReference(field.Argument.Type); + if (field.Argument.Value != null) + { + module.ImportReference(field.Argument.Value?.GetType()); + } + clonedAttribute.Fields.Add(field); + } + + // Return the cloned attribute. + return clonedAttribute; + } + + private static void Resolve(this Instruction instruction, MethodDefinition method_new, MethodDefinition method_original, ModuleDefinition module) + { + var operand = instruction.Operand; + if (operand == null) + return; + + if (operand is MethodDefinition opmtddef) + { + if (opmtddef.FullName.Equals(method_original.FullName)) + instruction.Operand = method_new; + else + instruction.Operand = module.ImportReference(opmtddef); + return; + } + + if (operand is MethodReference opmtdref) + { + instruction.Operand = module.ImportReference(opmtdref); + return; + } + + if (operand is FieldReference opfldref) + { + instruction.Operand = module.ImportReference(opfldref); + return; + } + + if (operand is TypeReference optyperef) + { + instruction.Operand = module.ImportReference(optyperef); + return; + } + } + + #endregion Clone + + // Extension methods for replacing references to a source type with references to a destination type within Mono.Cecil objects. + // This is used to ensure that copied fields, properties, and methods reference copied types instead of the originals. + #region UpdateTypes + + /// + /// Updates the InterfaceType of the given InterfaceImplementation, if it matches the source type, to the destination type. + /// + /// InterfaceImplementation that may have its InterfaceType updated. + /// The source type which could be replaced. + /// The destination type which could replace the source type. + public static void UpdateTypes(this InterfaceImplementation @interface, TypeDefinition src, TypeDefinition dest) + { + // If the interface's type matches the source type, update it to the destination type + if (@interface.InterfaceType == src) @interface.InterfaceType = dest; + } + + /// + /// Updates the FieldType of the given FieldDefinition, if it matches the source type, to the destination type. + /// + /// FieldDefinition that may have its FieldType updated. + /// The source type which could be replaced. + /// The destination type which could replace the source type. + public static void UpdateTypes(this FieldDefinition field, TypeDefinition src, TypeDefinition dest) + { + // If the field's type matches the source type, update it to the destination type + if (field.FieldType == src) field.FieldType = dest; + } + + /// + /// Updates the FieldReference and DeclaringType of the given FieldReference, if they match the source type, to the destination type. + /// If a matching field definition is found in the destination type, a reference to it is returned. + /// Otherwise, the original field reference is returned. + /// + /// FieldReference that may have its FieldType, and DeclaringType updated. + /// The source type which could be replaced. + /// The destination type which could replace the source type. + /// A FieldReference with updated types, or the original FieldReference if no updates were made. + public static FieldReference UpdateTypes(this FieldReference field, TypeDefinition src, TypeDefinition dest) + { + // Check if the field's FieldType or DeclaringType matches the source type, and if so, replace them with the destination type + if (field.FieldType == src) field.FieldType = dest; + if (field.DeclaringType == src) field.DeclaringType = dest; + + // Attempt to find a field in the destination type that matches the field's full name + // If a matching definition is found, return a reference to it otherwise return original reference + return dest.FindField(field.FullName) ?? field; + } + + /// + /// Updates the PropertyType of the given PropertyDefinition, if it matches the source type, to the destination type. + /// + /// PropertyDefinition that may have its PropertyType updated. + /// The source type which could be replaced. + /// The destination type which could replace the source type. + public static void UpdateTypes(this PropertyDefinition property, TypeDefinition src, TypeDefinition dest) + { + // If the property's type matches the source type, update it to the destination type + if (property.PropertyType == src) property.PropertyType = dest; + } + + /// + /// Updates the ParameterType of the given ParameterDefinition, if it matches the source type, to the destination type. + /// + /// ParameterDefinition that may have its ParameterType updated. + /// The source type which could be replaced. + /// The destination type which could replace the source type. + public static void UpdateTypes(this ParameterDefinition parameter, TypeDefinition src, TypeDefinition dest) + { + // If the parameter's type matches the source type, update it to the destination type + if (parameter.ParameterType == src) parameter.ParameterType = dest; + } + + /// + /// Updates the VariableType of the given VariableDefinition, if it matches the source type, to the destination type. + /// + /// VariableDefinition that may have its VariableType updated. + /// The source type which could be replaced. + /// The destination type which could replace the source type. + public static void UpdateTypes(this VariableDefinition variable, TypeDefinition src, TypeDefinition dest) + { + // If the variable's type matches the source type, update it to the destination type + if (variable.VariableType == src) variable.VariableType = dest; + } + + /// + /// Updates the ReturnType of the given MethodDefinition, if it matches the source type, to the destination type. + /// Also updates ParameterTypes and VariableTypes of the MethodDefinition using the same rule. + /// + /// MethodDefinition that may have its ReturnType, ParameterTypes, and VariableTypes updated. + /// The source type which could be replaced. + /// The destination type which could replace the source type. + public static void UpdateTypes(this MethodDefinition method, TypeDefinition src, TypeDefinition dest) + { + // Update method overrides if they match the source type + for (int i = 0; i < method.Overrides.Count; i++) method.Overrides[i] = method.Overrides[i].UpdateTypes(src, dest); + + // If the method's return type matches the source type, update it to the destination type + if (method.ReturnType == src) method.ReturnType = dest; + + // Update method parameters and variables if they match the source type + foreach (var parameter in method.Parameters) parameter.UpdateTypes(src, dest); + if (method.HasBody) foreach (var variable in method.Body.Variables) variable.UpdateTypes(src, dest); + } + + /// + /// Updates the ReturnType and DeclaringType of the given MethodReference, if they match the source type, to the destination type. + /// Also updates the ParameterTypes of the MethodReference using the same rule. + /// If a matching method definition is found in the destination type, a reference to it is returned. + /// Otherwise, the original method reference is returned. + /// + /// MethodReference that may have its ReturnType, DeclaringType and ParameterTypes updated. + /// The source type which could be replaced. + /// The destination type which could replace the source type. + /// A MethodReference with updated types, or the original MethodReference if no updates were made. + public static MethodReference UpdateTypes(this MethodReference method, TypeDefinition src, TypeDefinition dest) + { + // Update method parameters to destination type + foreach (var parameter in method.Parameters) parameter.UpdateTypes(src, dest); + + // Check if the method's ReturnType or DeclaringType matches the source type, and if so, replace them with the destination type + if (method.ReturnType == src) method.ReturnType = dest; + if (method.DeclaringType == src) method.DeclaringType = dest; + + // Attempt to find a method in the destination type that matches the method's full name + // If a matching definition is found, return a reference to it otherwise return original reference + return dest.FindMethod(method.FullName) ?? method; + } + + /// + /// Updates the ReturnType and Parameters of the CallSite to the destination type, if they match the source type, to the destination type. + /// + /// CallSite that needs its return type and parameters updated. + /// The original type which is being replaced. + /// The new type which is replacing the original type. + public static void UpdateTypes(this CallSite callSite, TypeDefinition src, TypeDefinition dest) + { + // Update callsite parameters to destination type + foreach (var parameter in callSite.Parameters) parameter.UpdateTypes(src, dest); + + // If the current return type is the source type, update it to destination type + if (callSite.ReturnType == src) callSite.ReturnType = dest; + } + + #endregion UpdateTypes + + // Extension methods for replacing references to a source type with references to a destination type within Mono.Cecil.Instruction objects. + // This is crucial for ensuring that the instructions within methods correctly reference the fields, properties, and methods of the destination type after cloning from the source type. + #region UpdateInstructionTypes + + /// + /// Updates the Operand of an instruction when merging classes. + /// The update strategy depends on the type of the operand. + /// If the operand is a ParameterDefinition, VariableDefinition, FieldReference, MethodReference, CallSite, or TypeReference, it's updated accordingly. + /// + /// Instruction that needs its operand updated. + /// The original type which is being replaced. + /// The new type which is replacing the original type. + public static void UpdateInstructionTypes(this Instruction instruction, TypeDefinition src, TypeDefinition dest) + { + // Check operand type and update accordingly + if (instruction.Operand is ParameterDefinition parameter) + parameter.UpdateTypes(src, dest); // Update types in ParameterDefinition + else if (instruction.Operand is VariableDefinition variable) + variable.UpdateTypes(src, dest); // Update types in VariableDefinition + else if (instruction.Operand is TypeReference type && type == src) + instruction.Operand = dest; // Update type in TypeReference + else if (instruction.Operand is FieldReference field) + instruction.Operand = field.UpdateTypes(src, dest); // Update types in FieldReference + else if (instruction.Operand is MethodReference method) + instruction.Operand = method.UpdateTypes(src, dest); // Update types in MethodReference + else if (instruction.Operand is CallSite callSite) + callSite.UpdateTypes(src, dest); // Update types in CallSite + } + + /// + /// Updates all instructions in the method's body. + /// + /// Method whose instructions are to be updated. + /// The original type which is being replaced. + /// The new type which is replacing the original type. + public static void UpdateInstructionTypes(this MethodDefinition method, TypeDefinition src, TypeDefinition dest) + { + // Update instructions in the method body to the destination type + if (method.HasBody) foreach (var instruction in method.Body.Instructions) UpdateInstructionTypes(instruction, src, dest); + } + + #endregion UpdateInstructionTypes + + // Extension methods for replacing references to a source type with references to a destination type within Mono.Cecil.Property getter and setter methods. + // This ensures that the properties of the destination type reference copied getters and setters instead of the originals. + #region UpdateGettersAndSetters + + /// + /// Updates the getter and setter methods of a property to reference the destination type when merging classes. + /// This method does the following: + /// - Clones the existing getter/setter methods, so that any modifications do not affect the original methods + /// - Calls UpdateTypes to update all type references within the methods' bodies from src to dest + /// - Updates the declaring type of the methods to be dest + /// - Finds the equivalent methods in dest (if they exist), and updates the property's getter/setter methods to reference them + /// This ensures that the property correctly interacts with the destination type after merging. + /// + /// PropertyDefinition whose getter and setter need to be updated. + /// The original type which is being replaced. + /// The new type which is replacing the original type. + public static void UpdateGettersAndSetters(this PropertyDefinition property, TypeDefinition src, TypeDefinition dest) + { + // If the declaring type of the property is the destination type + if (property.DeclaringType == dest) + { + // If the property has a getter, clone and update it + if (property.GetMethod != null) + { + // Clone the getter + var clonedGetter = property.GetMethod.Clone(); + // Update all type references within the getter from src to dest + clonedGetter.UpdateTypes(src, dest); + // Update the declaring type of the getter to be dest + clonedGetter.DeclaringType = dest; + // If an equivalent method exists in dest, update the property's getter to reference it + if (dest.FindMethod(clonedGetter.FullName) is MethodDefinition getMethod) + property.GetMethod = getMethod; + } + // If the property has a setter, clone and update it + if (property.SetMethod != null) + { + // Clone the setter + var clonedSetter = property.SetMethod.Clone(); + // Update all type references within the setter from src to dest + clonedSetter.UpdateTypes(src, dest); + // Update the declaring type of the setter to be dest + clonedSetter.DeclaringType = dest; + // If an equivalent method exists in dest, update the property's setter to reference it + if (dest.FindMethod(clonedSetter.FullName) is MethodDefinition setMethod) + property.SetMethod = setMethod; + } + } + } + + #endregion UpdateGettersAndSetters + + // Extension methods to import references from one module to another. + // This is important when merging assemblies classes as it allows the destination to access types that may not have been referenced prior. + #region ImportReferences + + /// + /// Imports the constructor reference for a given attribute into a module. + /// + /// The custom attribute whose constructor reference needs to be imported. + /// The module type into whose module the reference should be imported. + public static void ImportReferences(this CustomAttribute attribute, ModuleDefinition module) + { + // Import the constructor reference into the module + attribute.Constructor = module.ImportReference(attribute.Constructor); + } + + /// + /// Imports the interface type and custom attributes references of an interface into a module. + /// + /// The interface whose references need to be imported. + /// The module type into whose module the references should be imported. + public static void ImportReferences(this InterfaceImplementation @interface, ModuleDefinition module) + { + // Import the custom attributes references into the module + foreach (var attribute in @interface.CustomAttributes) attribute.ImportReferences(module); + + // Import the interface type reference into the module + @interface.InterfaceType = module.ImportReference(@interface.InterfaceType); + } + + /// + /// Imports the field type and custom attributes references of a field into a module. + /// + /// The field whose references need to be imported. + /// The module type into whose module the references should be imported. + public static void ImportReferences(this FieldDefinition field, ModuleDefinition module) + { + // Import the custom attributes references into the module + foreach (var attribute in field.CustomAttributes) attribute.ImportReferences(module); + + // Import the field type reference into the module + field.FieldType = module.ImportReference(field.FieldType); + + // Import the declaring type definition into the module + field.DeclaringType = module.ImportReference(field.DeclaringType).Resolve(); + } + + /// + /// Imports the property type and custom attributes references of a property into a module. + /// + /// The property whose references need to be imported. + /// The module type into whose module the references should be imported. + public static void ImportReferences(this PropertyDefinition property, ModuleDefinition module) + { + // Import the custom attributes references into the module + foreach (var attribute in property.CustomAttributes) attribute.ImportReferences(module); + + // Import the property type reference into the module + property.PropertyType = module.ImportReference(property.PropertyType); + + // Import the declaring type definition into the module + property.DeclaringType = module.ImportReference(property.DeclaringType).Resolve(); + } + + /// + /// Imports the parameter type and custom attributes references of a parameter into a module. + /// + /// The parameter whose references need to be imported. + /// The module type into whose module the references should be imported. + public static void ImportReferences(this ParameterDefinition parameter, ModuleDefinition module) + { + // Import the custom attributes references into the module + foreach (var attribute in parameter.CustomAttributes) attribute.ImportReferences(module); + + // Import the parameter type reference into the module + parameter.ParameterType = module.ImportReference(parameter.ParameterType); + } + + /// + /// Imports the variable type references of a variable into a module. + /// + /// The variable whose type references need to be imported. + /// The module type into whose module the references should be imported. + public static void ImportReferences(this VariableDefinition variable, ModuleDefinition module) + { + // Import the variable type reference into the module + variable.VariableType = module.ImportReference(variable.VariableType); + } + + /// + /// Imports the method type references and the custom attributes of a method into a module. + /// + /// The method whose references need to be imported. + /// The module type into whose module the references should be imported. + public static void ImportReferences(this MethodDefinition method, ModuleDefinition module) + { + // Import method overrides into the module + for (int i = 0; i < method.Overrides.Count; ++i) method.Overrides[i] = module.ImportReference(method.Overrides[i]); + + // Import the custom attributes references into the module + foreach (var attribute in method.CustomAttributes) attribute.ImportReferences(module); + + // Import the parameter type references into the module + foreach (var parameter in method.Parameters) parameter.ImportReferences(module); + + // Import the return type reference into the module + method.ReturnType = module.ImportReference(method.ReturnType); + + // Import the declaring type definition into the module + method.DeclaringType = module.ImportReference(method.DeclaringType).Resolve(); + + // If the method has a body, import references for each variable and instruction + if (method.HasBody) + { + // Import the variable type references in the method body into the module + foreach (var variable in method.Body.Variables) variable.ImportReferences(module); + + // Import the instruction type references in the method body into the module + foreach (var instruction in method.Body.Instructions) instruction.ImportReferences(module); + } + } + + /// + /// Imports the return type references of a CallSite into a module. + /// + /// The CallSite whose return type references need to be imported. + /// The module type into whose module the references should be imported. + public static void ImportReferences(this CallSite callSite, ModuleDefinition module) + { + // Import the return type reference of the callSite into the module + callSite.ReturnType = module.ImportReference(callSite.ReturnType); + } + + /// + /// Imports the operand type references of an instruction into a module. + /// + /// The instruction whose operand references need to be imported. + /// The module type into whose module the references should be imported. + public static void ImportReferences(this Instruction instruction, ModuleDefinition module) + { + // Import the operand references of the instruction into the module + if (instruction.Operand is ParameterDefinition parameter) + parameter.ImportReferences(module); + else if (instruction.Operand is VariableDefinition variable) + variable.ImportReferences(module); + else if (instruction.Operand is TypeReference type) + instruction.Operand = module.ImportReference(type); + else if (instruction.Operand is FieldReference field) + instruction.Operand = module.ImportReference(field); + else if (instruction.Operand is MethodReference method) + instruction.Operand = module.ImportReference(method); + else if (instruction.Operand is CallSite callSite) + callSite.ImportReferences(module); + } + + #endregion ImportReferences + + // Extension methods for swapping method implementations between different types. + // This can be used when wanting to replace method functionality in the destination type with the corresponding functionality from the source type. + #region SwapMethods + + /// + /// Swaps the method references within the provided instruction between two given methods. + /// + /// The instruction to modify. + /// The first method to swap. + /// The second method to swap. + public static void SwapMethodReferences(this Instruction instruction, MethodDefinition leftMethod, MethodDefinition rightMethod) + { + // If the instruction's operand is a method reference + if (instruction.Operand is MethodReference method) + { + // If the operand matches the left method, replace it with the right method + if (method == leftMethod) + instruction.Operand = rightMethod; + // If the operand matches the right method, replace it with the left method + else if (method == rightMethod) + instruction.Operand = leftMethod; + } + } + + /// + /// Swaps the method references within the provided collection of instructions between two given methods. + /// + /// The collection of instructions to modify. + /// The first method to swap. + /// The second method to swap. + public static void SwapMethodReferences(this Collection instructions, MethodDefinition leftMethod, MethodDefinition rightMethod) + { + // Swap method references for each instruction in the collection + foreach (var instruction in instructions) + instruction.SwapMethodReferences(leftMethod, rightMethod); + } + + /// + /// Swaps the method references within the body of the provided method between two given methods. + /// + /// The method to modify. + /// The first method to swap. + /// The second method to swap. + public static void SwapMethodReferences(this MethodDefinition method, MethodDefinition leftMethod, MethodDefinition rightMethod) + { + // Swap method references for each instruction in the method's body + if (method.HasBody) method.Body.Instructions.SwapMethodReferences(leftMethod, rightMethod); + } + + /// + /// Swaps the attributes, parameters, custom attributes, and generic parameters between two given methods. + /// + /// The first method to swap. + /// The second method to swap. + public static void SwapMethods(this MethodDefinition leftMethod, MethodDefinition rightMethod) + { + // Save the left method's original details + var leftBody = leftMethod.Body; + var leftAttributes = leftMethod.Attributes; + var leftImplAttributes = leftMethod.ImplAttributes; + var leftSemanticsAttributes = leftMethod.SemanticsAttributes; + var leftParameters = new Collection(leftMethod.Parameters); + var leftCustomAttributes = new Collection(leftMethod.CustomAttributes); + var leftGenericParameters = new Collection(leftMethod.GenericParameters); + + // Swap the details from the right method to the left + leftMethod.Body = rightMethod.Body; + leftMethod.Body = rightMethod.Body; + leftMethod.Attributes = rightMethod.Attributes; + leftMethod.ImplAttributes = rightMethod.ImplAttributes; + leftMethod.SemanticsAttributes = rightMethod.SemanticsAttributes; + leftMethod.Parameters.Clear(); + leftMethod.CustomAttributes.Clear(); + leftMethod.GenericParameters.Clear(); + foreach (var parameter in rightMethod.Parameters) leftMethod.Parameters.Add(parameter); + foreach (var attribute in rightMethod.CustomAttributes) leftMethod.CustomAttributes.Add(attribute); + foreach (var parameter in rightMethod.GenericParameters) leftMethod.GenericParameters.Add(parameter); + + // Swap the details from the left method (which were saved) to the right + rightMethod.Body = leftBody; + rightMethod.Body = leftBody; + rightMethod.Attributes = leftAttributes; + rightMethod.ImplAttributes = leftImplAttributes; + rightMethod.SemanticsAttributes = leftSemanticsAttributes; + rightMethod.Parameters.Clear(); + rightMethod.CustomAttributes.Clear(); + rightMethod.GenericParameters.Clear(); + foreach (var parameter in leftParameters) rightMethod.Parameters.Add(parameter); + foreach (var attribute in leftCustomAttributes) rightMethod.CustomAttributes.Add(attribute); + foreach (var parameter in leftGenericParameters) rightMethod.GenericParameters.Add(parameter); + + // Swap method references within each method body + leftMethod.SwapMethodReferences(leftMethod, rightMethod); + rightMethod.SwapMethodReferences(rightMethod, leftMethod); + } + + /// + /// Finds and swaps methods with the same full name within the given type. + /// + /// The type to modify. + /// Avoid signature conflicts by changing original method parameters to be base object types + public static void SwapDuplicateMethods(this TypeDefinition type, bool avoidSignatureConflicts = false) + { + // This HashSet is used for tracking the methods that have already been swapped. + var alreadySwapped = new HashSet(); + + // Convert the method collection to list for efficient index-based access. + var methods = type.Methods.ToList(); + + // Iterate over each pair of methods in the type + for (int i = 0; i < methods.Count; i++) + { + for (int j = i + 1; j < methods.Count; j++) + { + var methodLeft = methods[i]; + var methodRight = methods[j]; + + // If two methods have the same full name and haven't been swapped yet + if (methodLeft.FullName == methodRight.FullName && !alreadySwapped.Contains(methodLeft.FullName)) + { + // Add the method full name to the set of already swapped methods + _ = alreadySwapped.Add(methodLeft.FullName); + // Swap the two methods + methodLeft.SwapMethods(methodRight); + + // Change the original method types to be generic to avoid signature conflicts + if (avoidSignatureConflicts) + { + foreach (var parameter in methodRight.Parameters) + if (!parameter.ParameterType.IsValueType) parameter.ParameterType = type.Module.ImportReference(typeof(object)); + } + } + } + } + } + + #endregion SwapMethods + + // Methods to do with instruction optimizations + #region InstructionOptimizations + +#pragma warning disable RCS1003 + /// + /// Determines if a given instruction within a method can be optimized out. + /// Specifically, this method looks for type conversion instructions (Isinst or Castclass) + /// that are unnecessary because the type of the value at the top of the stack is + /// already the target conversion type. + /// + /// The instruction to be checked for optimization. + /// The method definition that contains the instruction. + /// Returns true if the instruction can be optimized out. Otherwise, returns false. + /// + /// This method works by examining the instructions before the given instruction in the method, + /// maintaining a conceptual "stack balance" and tracking the type of the value at the top of the stack. + /// The stack balance is a measure of the net effect of the instructions on the stack, + /// with a positive balance indicating more values have been pushed than popped, + /// and a negative balance indicating more values have been popped than pushed. + /// If the stack balance is zero and the type of the value at the top of the stack + /// matches the type conversion, the conversion is unnecessary and the method returns true. + /// + public static bool CanBeOptimizedOut(this Instruction instruction, MethodDefinition method) + { + // Check if the instruction is a type conversion instruction (instance cast or class cast) + if (instruction.OpCode == OpCodes.Isinst || instruction.OpCode == OpCodes.Castclass) + { + // Get the type to which the conversion is being made + var typeConversionType = instruction.Operand as TypeReference; + // Initialize stack balance. This will help to determine the net stack effect of the instructions + int stackBalance = 0; + // Move to the previous instruction + instruction = instruction.Previous; + + // Process previous instructions + while (instruction != null) + { + // Determine how the current instruction modifies the stack + var pushBehaviour = instruction.OpCode.StackBehaviourPush; + var popBehaviour = instruction.OpCode.StackBehaviourPop; + + // Fullname of any type extracted from the instruction + string extractedFullName = null; + + // This is an exhaustive check for control flow change instructions. These instructions will cause a jump + // in execution or a termination of the function, thus ending our analysis. + if (instruction.OpCode == OpCodes.Ret || // Return from the current method. + instruction.OpCode == OpCodes.Throw || // Throw an exception. + instruction.OpCode == OpCodes.Rethrow || // Rethrow the current exception. + instruction.OpCode == OpCodes.Endfilter || // End the filter clause of an exception block and branch to the exception handler. + instruction.OpCode == OpCodes.Endfinally || // Transfer control from the exception block of a try or catch block. + instruction.OpCode == OpCodes.Leave || instruction.OpCode == OpCodes.Leave_S || // Exit a protected region of code. + instruction.OpCode == OpCodes.Jmp || // Jump to the method pointed to by the method pointer loaded on the stack. + instruction.OpCode == OpCodes.Switch || // Switch control to one of several locations. + instruction.OpCode == OpCodes.Br || instruction.OpCode == OpCodes.Br_S || // Unconditional branch to target. + instruction.OpCode == OpCodes.Brfalse || instruction.OpCode == OpCodes.Brfalse_S || // Branch to target if value is zero (false). + instruction.OpCode == OpCodes.Brtrue || instruction.OpCode == OpCodes.Brtrue_S || // Branch to target if value is non-zero (true). + instruction.OpCode == OpCodes.Beq || instruction.OpCode == OpCodes.Beq_S || // Branch to target if two values are equal. + instruction.OpCode == OpCodes.Bne_Un || instruction.OpCode == OpCodes.Bne_Un_S || // Branch to target if two values are not equal. + instruction.OpCode == OpCodes.Bge || instruction.OpCode == OpCodes.Bge_S || instruction.OpCode == OpCodes.Bge_Un || instruction.OpCode == OpCodes.Bge_Un_S || // Branch to target if value1 >= value2 (unsigned or unordered). + instruction.OpCode == OpCodes.Bgt || instruction.OpCode == OpCodes.Bgt_S || instruction.OpCode == OpCodes.Bgt_Un || instruction.OpCode == OpCodes.Bgt_Un_S || // Branch to target if value1 > value2 (unsigned or unordered). + instruction.OpCode == OpCodes.Ble || instruction.OpCode == OpCodes.Ble_S || instruction.OpCode == OpCodes.Ble_Un || instruction.OpCode == OpCodes.Ble_Un_S || // Branch to target if value1 <= value2 (unsigned or unordered). + instruction.OpCode == OpCodes.Blt || instruction.OpCode == OpCodes.Blt_S || instruction.OpCode == OpCodes.Blt_Un || instruction.OpCode == OpCodes.Blt_Un_S) // Branch to target if value1 < value2 (unsigned or unordered). + return false; // Return from method + + // Check if instruction is for loading a field onto the stack + // In this case, the type of the value is the type of the field. + else if (instruction.OpCode == OpCodes.Ldfld || // load field value onto stack + instruction.OpCode == OpCodes.Ldflda || // load field address onto stack + instruction.OpCode == OpCodes.Ldsfld || // load static field value onto stack + instruction.OpCode == OpCodes.Ldsflda) // load static field address onto stack + extractedFullName = ((FieldReference)instruction.Operand).FieldType.FullName; + + // Check if instruction is for loading an argument onto the stack + // In this case, the type of the value is the type of the argument. + else if (instruction.OpCode == OpCodes.Ldarg || // load argument onto stack + instruction.OpCode == OpCodes.Ldarg_S) // short form for loading argument onto stack + extractedFullName = ((ParameterReference)instruction.Operand).ParameterType.FullName; + + // Check for loading argument at index 0 onto stack + else if (instruction.OpCode == OpCodes.Ldarg_0) // load argument at index 0 onto stack + extractedFullName = (method.IsStatic ? method.Parameters[0].ParameterType : method.DeclaringType).FullName; + // Check for loading argument at index 1 onto stack + else if (instruction.OpCode == OpCodes.Ldarg_1) // load argument at index 1 onto stack + extractedFullName = (method.IsStatic ? method.Parameters[1].ParameterType : method.Parameters[0].ParameterType).FullName; + // Check for loading argument at index 2 onto stack + else if (instruction.OpCode == OpCodes.Ldarg_2) // load argument at index 2 onto stack + extractedFullName = (method.IsStatic ? method.Parameters[2].ParameterType : method.Parameters[1].ParameterType).FullName; + // Check for loading argument at index 3 onto stack + else if (instruction.OpCode == OpCodes.Ldarg_3) // load argument at index 3 onto stack + extractedFullName = (method.IsStatic ? method.Parameters[3].ParameterType : method.Parameters[2].ParameterType).FullName; + + // Check for loading local variable onto stack + else if (instruction.OpCode == OpCodes.Ldloc || // load local variable onto stack + instruction.OpCode == OpCodes.Ldloc_S) // short form for loading local variable onto stack + extractedFullName = ((VariableReference)instruction.Operand).VariableType.FullName; + // Check for loading local variable at index 0 onto stack + else if (instruction.OpCode == OpCodes.Ldloc_0) // load local variable at index 0 onto stack + extractedFullName = method.Body.Variables[0].VariableType.FullName; + // Check for loading local variable at index 1 onto stack + else if (instruction.OpCode == OpCodes.Ldloc_1)// load local variable at index 1 onto stack + extractedFullName = method.Body.Variables[1].VariableType.FullName; + // Check for loading local variable at index 2 onto stack + else if (instruction.OpCode == OpCodes.Ldloc_2)// load local variable at index 2 onto stack + extractedFullName = method.Body.Variables[2].VariableType.FullName; + // Check for loading local variable at index 3 onto stack + else if (instruction.OpCode == OpCodes.Ldloc_3)// load local variable at index 3 onto stack + extractedFullName = method.Body.Variables[3].VariableType.FullName; + + // Check for calling a method and pushing return value onto the stack, loading function pointer onto the stack + else if (instruction.OpCode == OpCodes.Callvirt || // call method virtually and push return value onto stack + instruction.OpCode == OpCodes.Call || // call method and push return value onto stack + instruction.OpCode == OpCodes.Ldftn || // load method pointer onto stack + instruction.OpCode == OpCodes.Ldvirtftn) // load virtual method pointer onto stack + extractedFullName = ((MethodReference)instruction.Operand).ReturnType.FullName; + + // Check for calling a method indicated on the stack with arguments, pushing return value onto stack + else if (instruction.OpCode == OpCodes.Calli) // call method indicated on the stack with arguments, pushing return value onto stack + extractedFullName = ((CallSite)instruction.Operand).ReturnType.FullName; + + // Check for creating a new object and pushing object reference onto stack + else if (instruction.OpCode == OpCodes.Newobj) // create a new object and push object reference onto stack + extractedFullName = ((MethodReference)instruction.Operand).DeclaringType.FullName; + + // Check for loading an object, array element, or pointer onto stack, creating a new array, or creating a typed reference + else if (instruction.OpCode == OpCodes.Ldobj || // load object onto stack + instruction.OpCode == OpCodes.Ldelem_Any || // load element of an object array onto stack + instruction.OpCode == OpCodes.Newarr || // create a new array and push reference onto stack + instruction.OpCode == OpCodes.Mkrefany) // push a typed reference onto stack + extractedFullName = ((TypeReference)instruction.Operand).FullName; + + // Check for loading a string onto stack + else if (instruction.OpCode == OpCodes.Ldstr) // load a string onto stack + extractedFullName = typeof(string).FullName; + + // If the type of the value currently at the top of the stack matches the type conversion + // and the stack is balanced, the conversion is unnecessary + if (stackBalance == 0 && extractedFullName == typeConversionType.FullName) + return true; + + // Dup doesn't change the type of the top of the stack, so adjust stack balance to ignore it + if (instruction.OpCode == OpCodes.Dup) + stackBalance--; + + // Adjust stack balance according to the current instruction's push behavior + //if (pushBehaviour == StackBehaviour.Push0) + if (pushBehaviour == StackBehaviour.Push1 || pushBehaviour == StackBehaviour.Pushi || pushBehaviour == StackBehaviour.Pushref || + pushBehaviour == StackBehaviour.Pushi8 || pushBehaviour == StackBehaviour.Pushr4 || pushBehaviour == StackBehaviour.Pushr8 || + pushBehaviour == StackBehaviour.Varpush) + stackBalance++; + else if (pushBehaviour == StackBehaviour.Push1_push1) + stackBalance += 2; + + // Adjust stack balance according to the current instruction's pop behavior + //if (popBehaviour == StackBehaviour.Pop0) + if (popBehaviour == StackBehaviour.Pop1 || popBehaviour == StackBehaviour.Popi || popBehaviour == StackBehaviour.Popref || + popBehaviour == StackBehaviour.Varpop) + stackBalance--; + else if (popBehaviour == StackBehaviour.Pop1_pop1 || popBehaviour == StackBehaviour.Popi_popi || popBehaviour == StackBehaviour.Popi_pop1 || + popBehaviour == StackBehaviour.Popi_popi8 || popBehaviour == StackBehaviour.Popi_popr4 || popBehaviour == StackBehaviour.Popi_popr8 || + popBehaviour == StackBehaviour.Popref_pop1 || popBehaviour == StackBehaviour.Popref_popi) + stackBalance -= 2; + else if (popBehaviour == StackBehaviour.Popi_popi_popi || popBehaviour == StackBehaviour.Popref_popi_popi || popBehaviour == StackBehaviour.Popref_popi_popi8 || + popBehaviour == StackBehaviour.Popref_popi_popr4 || popBehaviour == StackBehaviour.Popref_popi_popr8 || popBehaviour == StackBehaviour.Popref_popi_popref) + stackBalance -= 3; + + // Move to previous instruction + instruction = instruction.Previous; + } + } + + // Return that the instruction cannot be optimized + return false; + } +#pragma warning restore RCS1003 + + /// + /// Optimizes a given method by removing any instructions + /// that can be optimized out. + /// + /// + /// The MethodDefinition object to be optimized. This method contains a list + /// of instructions that are to be checked and potentially removed if they can be optimized out. + /// + public static void OptimizeInstructions(this MethodDefinition method) + { + // If the method doesn't have a body (i.e., it's an abstract or external method), then exit + if (!method.HasBody) return; + + // Iterate over each instruction in the method body + for (int i = 0; i < method.Body.Instructions.Count - 1; ++i) + { + // If the current instruction can be optimized out according to the CanBeOptimizedOut method, remove it + if (method.Body.Instructions[i].CanBeOptimizedOut(method)) + { + // Remove the current instruction from the method body + method.Body.Instructions.RemoveAt(i); + + // Decrement the loop index to account for the removal. This ensures that the next iteration doesn't skip any instructions. + i--; + } + } + } + + #endregion InstructionOptimizations +} diff --git a/Scripts/Utilities/MultiActionProjectileRewrites.cs b/Scripts/Utilities/MultiActionProjectileRewrites.cs new file mode 100644 index 0000000..0202031 --- /dev/null +++ b/Scripts/Utilities/MultiActionProjectileRewrites.cs @@ -0,0 +1,738 @@ +using KFCommonUtilityLib.Scripts.StaticManagers; +using System.Collections.Generic; +using UnityEngine; + +namespace KFCommonUtilityLib.Scripts.Utilities +{ + /// + /// This new script make following changes: + /// - projectile ItemValue fields are reused for custom passive calculation: + /// -- Meta => launcher ItemClass id + /// -- SelectedAmmoIndex => launcher action index + /// -- Activated => launcher data strain perc + /// -- cosmetics and mods reference launcher ItemValue + /// -- Quality and Durability is copied from launcher ItemValue + /// - MinEventParams.itemActionData is set to correct launcher data. + /// + public class CustomProjectileMoveScript : ProjectileMoveScript + { + public override void checkCollision() + { + if (this.firingEntity == null || state != State.Active || gameManager == null) + return; + World world = gameManager?.World; + if (world == null) + { + return; + } + Vector3 checkPos; + if (bOnIdealPos) + { + checkPos = transform.position + Origin.position; + } + else + { + checkPos = idealPosition; + } + Vector3 dir = checkPos - previousPosition; + float magnitude = dir.magnitude; + if (magnitude < 0.04f) + { + return; + } + EntityAlive firingEntity = (EntityAlive)this.firingEntity; + Ray ray = new Ray(previousPosition, dir.normalized); + waterCollisionParticles.CheckCollision(ray.origin, ray.direction, magnitude, (firingEntity != null) ? firingEntity.entityId : (-1)); + int prevLayer = 0; + if (firingEntity != null && firingEntity.emodel != null) + { + prevLayer = firingEntity.GetModelLayer(); + firingEntity.SetModelLayer(2); + } + int hitmask = ((hmOverride == 0) ? 80 : hmOverride); + bool flag = Voxel.Raycast(world, ray, magnitude, -538750997, hitmask, 0); + if (firingEntity != null && firingEntity.emodel != null) + { + firingEntity.SetModelLayer(prevLayer); + } + if (flag && (GameUtils.IsBlockOrTerrain(Voxel.voxelRayHitInfo.tag) || Voxel.voxelRayHitInfo.tag.StartsWith("E_"))) + { + if (firingEntity != null && !firingEntity.isEntityRemote) + { + firingEntity.MinEventContext.Other = ItemActionAttack.FindHitEntity(Voxel.voxelRayHitInfo) as EntityAlive; + firingEntity.MinEventContext.ItemActionData = actionData; + firingEntity.MinEventContext.ItemValue = itemValueLauncher; + firingEntity.MinEventContext.Position = Voxel.voxelRayHitInfo.hit.pos; + ItemActionAttack.AttackHitInfo attackHitInfo = new ItemActionAttack.AttackHitInfo + { + WeaponTypeTag = ItemActionAttack.RangedTag + }; + float strainPerc = itemValueProjectile.Activated / (float)byte.MaxValue; + MultiActionProjectileRewrites.ProjectileHit(Voxel.voxelRayHitInfo, + ProjectileOwnerID, + EnumDamageTypes.Piercing, + Mathf.Lerp(1f, MultiActionProjectileRewrites.GetProjectileDamageBlock(itemActionProjectile, itemValueProjectile, ItemActionAttack.GetBlockHit(world, Voxel.voxelRayHitInfo), firingEntity, actionData.indexInEntityOfAction), strainPerc), + Mathf.Lerp(1f, MultiActionProjectileRewrites.GetProjectileDamageEntity(itemActionProjectile, itemValueProjectile, firingEntity, actionData.indexInEntityOfAction), strainPerc), + 1f, + 1f, + MultiActionReversePatches.ProjectileGetValue(PassiveEffects.CriticalChance, itemValueProjectile, itemProjectile.CritChance.Value, firingEntity, null, itemProjectile.ItemTags, true, false), + ItemAction.GetDismemberChance(actionData, Voxel.voxelRayHitInfo), + itemProjectile.MadeOfMaterial.SurfaceCategory, + itemActionProjectile.GetDamageMultiplier(), + getBuffActions(), + attackHitInfo, + 1, + itemActionProjectile.ActionExp, + itemActionProjectile.ActionExpBonusMultiplier, + null, + null, + ItemActionAttack.EnumAttackMode.RealNoHarvesting, + null, + -1, + itemValueProjectile, + itemValueLauncher); + if (firingEntity.MinEventContext.Other == null) + { + firingEntity.FireEvent(MinEventTypes.onSelfPrimaryActionMissEntity, false); + } + firingEntity.FireEvent(MinEventTypes.onProjectileImpact, false); + MinEventParams.CachedEventParam.Self = firingEntity; + MinEventParams.CachedEventParam.Position = Voxel.voxelRayHitInfo.hit.pos; + MinEventParams.CachedEventParam.ItemValue = itemValueProjectile; + MinEventParams.CachedEventParam.ItemActionData = actionData; + MinEventParams.CachedEventParam.Other = firingEntity.MinEventContext.Other; + itemProjectile.FireEvent(MinEventTypes.onProjectileImpact, MinEventParams.CachedEventParam); + if (itemActionProjectile.Explosion.ParticleIndex > 0) + { + Vector3 vector3 = Voxel.voxelRayHitInfo.hit.pos - dir.normalized * 0.1f; + Vector3i vector3i = World.worldToBlockPos(vector3); + if (!world.GetBlock(vector3i).isair) + { + BlockFace blockFace; + vector3i = Voxel.OneVoxelStep(vector3i, vector3, -dir.normalized, out vector3, out blockFace); + } + gameManager.ExplosionServer(Voxel.voxelRayHitInfo.hit.clrIdx, vector3, vector3i, Quaternion.identity, itemActionProjectile.Explosion, ProjectileOwnerID, 0f, false, itemValueProjectile); + SetState(State.Dead); + return; + } + if (itemProjectile.IsSticky) + { + GameRandom gameRandom = world.GetGameRandom(); + if (GameUtils.IsBlockOrTerrain(Voxel.voxelRayHitInfo.tag)) + { + if (gameRandom.RandomFloat < MultiActionReversePatches.ProjectileGetValue(PassiveEffects.ProjectileStickChance, itemValueProjectile, 0.5f, firingEntity, null, itemProjectile.ItemTags | FastTags.Parse(Voxel.voxelRayHitInfo.fmcHit.blockValue.Block.blockMaterial.SurfaceCategory), true, false)) + { + RestoreProjectileValue(); + ProjectileID = ProjectileManager.AddProjectileItem(transform, -1, Voxel.voxelRayHitInfo.hit.pos, dir.normalized, itemValueProjectile.type); + SetState(State.Sticky); + } + else + { + gameManager.SpawnParticleEffectServer(new ParticleEffect("impact_metal_on_wood", Voxel.voxelRayHitInfo.hit.pos, Utils.BlockFaceToRotation(Voxel.voxelRayHitInfo.fmcHit.blockFace), 1f, Color.white, string.Format("{0}hit{1}", Voxel.voxelRayHitInfo.fmcHit.blockValue.Block.blockMaterial.SurfaceCategory, itemProjectile.MadeOfMaterial.SurfaceCategory), null), firingEntity.entityId, false, false); + SetState(State.Dead); + } + } + else if (gameRandom.RandomFloat < MultiActionReversePatches.ProjectileGetValue(PassiveEffects.ProjectileStickChance, itemValueProjectile, 0.5f, firingEntity, null, itemProjectile.ItemTags, true, false)) + { + RestoreProjectileValue(); + ProjectileID = ProjectileManager.AddProjectileItem(transform, -1, Voxel.voxelRayHitInfo.hit.pos, dir.normalized, itemValueProjectile.type); + Utils.SetLayerRecursively(ProjectileManager.GetProjectile(ProjectileID).gameObject, 14, null); + SetState(State.Sticky); + } + else + { + gameManager.SpawnParticleEffectServer(new ParticleEffect("impact_metal_on_wood", Voxel.voxelRayHitInfo.hit.pos, Utils.BlockFaceToRotation(Voxel.voxelRayHitInfo.fmcHit.blockFace), 1f, Color.white, "bullethitwood", null), firingEntity.entityId, false, false); + SetState(State.Dead); + } + } + else + { + SetState(State.Dead); + } + } + else + { + SetState(State.Dead); + } + + if (state == State.Active) + { + SetState(State.Dead); + } + } + previousPosition = checkPos; + } + + private void RestoreProjectileValue() + { + itemValueProjectile.Modifications = ItemValue.emptyItemValueArray; + itemValueProjectile.CosmeticMods = ItemValue.emptyItemValueArray; + itemValueProjectile.Quality = 0; + itemValueProjectile.UseTimes = 0; + itemValueProjectile.Meta = 0; + itemValueProjectile.SelectedAmmoTypeIndex = 0; + } + } + + public static class MultiActionProjectileRewrites + { + public static void ProjectileHit(WorldRayHitInfo hitInfo, int _attackerEntityId, EnumDamageTypes _damageType, float _blockDamage, + float _entityDamage, float _staminaDamageMultiplier, float _weaponCondition, float _criticalHitChanceOLD, + float _dismemberChance, string _attackingDeviceMadeOf, DamageMultiplier _damageMultiplier, + List _buffActions, ItemActionAttack.AttackHitInfo _attackDetails, int _flags = 1, int _actionExp = 0, + float _actionExpBonus = 0f, ItemActionAttack rangeCheckedAction = null, + Dictionary _toolBonuses = null, + ItemActionAttack.EnumAttackMode _attackMode = ItemActionAttack.EnumAttackMode.RealNoHarvesting, + Dictionary _hitSoundOverrides = null, int ownedEntityId = -1, ItemValue projectileValue = null, ItemValue launcherValue = null) + { + if (_attackDetails != null) + { + _attackDetails.hitPosition = Vector3i.zero; + _attackDetails.bKilled = false; + } + if (hitInfo == null || hitInfo.tag == null) + { + return; + } + World world = GameManager.Instance.World; + bool canHarvest = true; + if (_attackMode == ItemActionAttack.EnumAttackMode.RealNoHarvestingOrEffects) + { + canHarvest = false; + _attackMode = ItemActionAttack.EnumAttackMode.RealNoHarvesting; + } + if (_attackDetails != null) + { + _attackDetails.itemsToDrop = null; + _attackDetails.bBlockHit = false; + _attackDetails.entityHit = null; + } + string blockFaceParticle = null; + string surfaceCategory = null; + float lightValueAtBlockPos = 1f; + Color blockFaceColor = Color.white; + bool isProtectionApplied = false; + EntityAlive attackerEntity = world.GetEntity(_attackerEntityId) as EntityAlive; + bool isHoldingDamageItem = false; + if (attackerEntity != null) + { + if (launcherValue == null) + { + launcherValue = attackerEntity.inventory.holdingItemItemValue; + } + isHoldingDamageItem = launcherValue.Equals(attackerEntity.inventory.holdingItemItemValue); + } + bool isHitTargetPlayer = true; + //if hits block or terrain + if (GameUtils.IsBlockOrTerrain(hitInfo.tag)) + { + if (ItemAction.ShowDebugDisplayHit) + { + DebugLines.Create(null, attackerEntity.RootTransform, Camera.main.transform.position + Origin.position, hitInfo.hit.pos, new Color(1f, 0.5f, 1f), new Color(1f, 0f, 1f), ItemAction.DebugDisplayHitSize * 2f, ItemAction.DebugDisplayHitSize, ItemAction.DebugDisplayHitTime); + } + ChunkCluster hittedChunk = world.ChunkClusters[hitInfo.hit.clrIdx]; + if (hittedChunk == null) + { + return; + } + Vector3i hitBlockPos = hitInfo.hit.blockPos; + BlockValue hitBlockValue = hittedChunk.GetBlock(hitBlockPos); + if (hitBlockValue.isair && hitInfo.hit.blockValue.Block.IsDistantDecoration && hitInfo.hit.blockValue.damage >= hitInfo.hit.blockValue.Block.MaxDamage - 1) + { + hitBlockValue = hitInfo.hit.blockValue; + world.SetBlockRPC(hitBlockPos, hitBlockValue); + } + Block hitBlock = hitBlockValue.Block; + if (hitBlock == null) + { + return; + } + if (hitBlockValue.ischild) + { + hitBlockPos = hitBlock.multiBlockPos.GetParentPos(hitBlockPos, hitBlockValue); + hitBlockValue = hittedChunk.GetBlock(hitBlockPos); + hitBlock = hitBlockValue.Block; + if (hitBlock == null) + { + return; + } + } + if (hitBlockValue.isair) + { + return; + } + float landProtectionModifier = 0; + if (!world.IsWithinTraderArea(hitInfo.hit.blockPos) && hitBlock.blockMaterial.id != "Mbedrock") + { + landProtectionModifier = world.GetLandProtectionHardnessModifier(hitInfo.hit.blockPos, attackerEntity, world.GetGameManager().GetPersistentLocalPlayer()); + } + if (landProtectionModifier != 1f) + { + if (attackerEntity && _attackMode != ItemActionAttack.EnumAttackMode.Simulate && attackerEntity is EntityPlayer && !launcherValue.ItemClass.ignoreKeystoneSound && !launcherValue.ToBlockValue().Block.IgnoreKeystoneOverlay) + { + attackerEntity.PlayOneShot("keystone_impact_overlay", false); + } + if (landProtectionModifier < 1f) + { + isProtectionApplied = true; + } + } + if (hitBlockPos != _attackDetails.hitPosition || landProtectionModifier != _attackDetails.hardnessScale || hitBlockValue.type != _attackDetails.blockBeingDamaged.type || (isHoldingDamageItem && projectileValue.SelectedAmmoTypeIndex != _attackDetails.ammoIndex)) + { + float finalHardness = Mathf.Max(hitBlock.GetHardness(), 0.1f) * landProtectionModifier; + float finalBlockDamage = _blockDamage * ((_damageMultiplier != null) ? _damageMultiplier.Get(hitBlock.blockMaterial.DamageCategory) : 1f); + if (attackerEntity) + { + finalBlockDamage *= attackerEntity.GetBlockDamageScale(); + } + if (_toolBonuses != null && _toolBonuses.Count > 0) + { + finalBlockDamage *= calculateHarvestToolDamageBonus(_toolBonuses, hitBlock.itemsToDrop); + _attackDetails.bHarvestTool = true; + } + _attackDetails.damagePerHit = isProtectionApplied ? 0f : (finalBlockDamage / finalHardness); + _attackDetails.damage = 0f; + _attackDetails.hardnessScale = landProtectionModifier; + _attackDetails.hitPosition = hitBlockPos; + _attackDetails.blockBeingDamaged = hitBlockValue; + if (isHoldingDamageItem) + { + _attackDetails.ammoIndex = projectileValue.SelectedAmmoTypeIndex; + } + } + _attackDetails.raycastHitPosition = hitInfo.hit.blockPos; + Block fmcHitBlock = hitInfo.fmcHit.blockValue.Block; + lightValueAtBlockPos = world.GetLightBrightness(hitInfo.fmcHit.blockPos); + blockFaceColor = fmcHitBlock.GetColorForSide(hitInfo.fmcHit.blockValue, hitInfo.fmcHit.blockFace); + blockFaceParticle = fmcHitBlock.GetParticleForSide(hitInfo.fmcHit.blockValue, hitInfo.fmcHit.blockFace); + MaterialBlock materialForSide = fmcHitBlock.GetMaterialForSide(hitInfo.fmcHit.blockValue, hitInfo.fmcHit.blockFace); + surfaceCategory = materialForSide.SurfaceCategory; + float modifiedBlockDamage = _attackDetails.damagePerHit * _staminaDamageMultiplier; + if (attackerEntity) + { + string blockFaceDamageCategory = materialForSide.DamageCategory ?? string.Empty; + modifiedBlockDamage = (int)MultiActionReversePatches.ProjectileGetValue(PassiveEffects.DamageModifier, projectileValue, modifiedBlockDamage, attackerEntity, null, FastTags.Parse(blockFaceDamageCategory) | _attackDetails.WeaponTypeTag | hitInfo.fmcHit.blockValue.Block.Tags, true, false); + } + modifiedBlockDamage = ItemActionAttack.DegradationModifier(modifiedBlockDamage, _weaponCondition); + modifiedBlockDamage = isProtectionApplied ? 0f : Utils.FastMax(1f, modifiedBlockDamage); + _attackDetails.damage += modifiedBlockDamage; + _attackDetails.bKilled = false; + _attackDetails.damageTotalOfTarget = hitBlockValue.damage + _attackDetails.damage; + if (_attackDetails.damage > 0f) + { + BlockFace blockFaceFromHitInfo = GameUtils.GetBlockFaceFromHitInfo(hitBlockPos, hitBlockValue, hitInfo.hitCollider, hitInfo.hitTriangleIdx, out _, out _); + int blockFaceTexture = hittedChunk.GetBlockFaceTexture(hitBlockPos, blockFaceFromHitInfo); + int blockCurDamage = hitBlockValue.damage; + bool isBlockBroken = blockCurDamage >= hitBlock.MaxDamage; + int ownerAttackerID = ((ownedEntityId != -1 && ownedEntityId != -2) ? ownedEntityId : _attackerEntityId); + int blockNextDamage = (_attackMode != ItemActionAttack.EnumAttackMode.Simulate) ? hitBlock.DamageBlock(world, hittedChunk.ClusterIdx, hitBlockPos, hitBlockValue, (int)_attackDetails.damage, ownerAttackerID, _attackDetails, _attackDetails.bHarvestTool, false) : 0; + if (blockNextDamage == 0) + { + _attackDetails.damage = 0f; + } + else + { + _attackDetails.damage -= blockNextDamage - blockCurDamage; + } + if (_attackMode != ItemActionAttack.EnumAttackMode.Simulate && canHarvest && attackerEntity is EntityPlayerLocal && blockFaceTexture > 0 && hitBlock.MeshIndex == 0 && blockNextDamage >= hitBlock.MaxDamage * 1f) + { + ParticleEffect particleEffect = new ParticleEffect("paint_block", hitInfo.fmcHit.pos - Origin.position, Utils.BlockFaceToRotation(hitInfo.fmcHit.blockFace), lightValueAtBlockPos, blockFaceColor, null, null) + { + opqueTextureId = BlockTextureData.list[blockFaceTexture].TextureID + }; + GameManager.Instance.SpawnParticleEffectClient(particleEffect, _attackerEntityId, false, false); + } + _attackDetails.damageGiven = ((!isBlockBroken) ? (blockNextDamage - blockCurDamage) : 0); + _attackDetails.damageMax = hitBlock.MaxDamage; + _attackDetails.bKilled = !isBlockBroken && blockNextDamage >= hitBlock.MaxDamage; + _attackDetails.itemsToDrop = hitBlock.itemsToDrop; + _attackDetails.bBlockHit = true; + _attackDetails.materialCategory = hitBlock.blockMaterial.SurfaceCategory; + if (attackerEntity != null && _attackMode != ItemActionAttack.EnumAttackMode.Simulate) + { + attackerEntity.MinEventContext.BlockValue = hitBlockValue; + attackerEntity.MinEventContext.Tags = hitBlock.Tags; + if (_attackDetails.bKilled) + { + attackerEntity.FireEvent(MinEventTypes.onSelfDestroyedBlock, isHoldingDamageItem); + attackerEntity.NotifyDestroyedBlock(_attackDetails); + } + else + { + attackerEntity.FireEvent(MinEventTypes.onSelfDamagedBlock, isHoldingDamageItem); + } + } + } + } + else if (hitInfo.tag.StartsWith("E_")) + { + Entity hitEntity = ItemActionAttack.FindHitEntityNoTagCheck(hitInfo, out string hitBodyPart); + if (hitEntity == null) + { + return; + } + if (hitEntity.entityId == _attackerEntityId) + { + return; + } + if (!hitEntity.CanDamageEntity(_attackerEntityId)) + { + return; + } + EntityAlive hitEntityAlive = hitEntity as EntityAlive; + DamageSourceEntity damageSourceEntity = new DamageSourceEntity(EnumDamageSource.External, _damageType, _attackerEntityId, hitInfo.ray.direction, hitInfo.transform.name, hitInfo.hit.pos, Voxel.phyxRaycastHit.textureCoord); + damageSourceEntity.AttackingItem = projectileValue; + damageSourceEntity.DismemberChance = _dismemberChance; + damageSourceEntity.CreatorEntityId = ownedEntityId; + bool isCriticalHit = _attackDetails.isCriticalHit; + int finalEntityDamage = (int)_entityDamage; + if (attackerEntity != null && hitEntityAlive != null) + { + FastTags equipmentTags = FastTags.none; + if (hitEntityAlive.Health > 0) + { + equipmentTags = FastTags.Parse(damageSourceEntity.GetEntityDamageEquipmentSlotGroup(hitEntityAlive).ToStringCached()); + equipmentTags |= DamagePatches.GetBodyPartTags(damageSourceEntity.GetEntityDamageBodyPart(hitEntityAlive)); + } + finalEntityDamage = (int)MultiActionReversePatches.ProjectileGetValue(PassiveEffects.DamageModifier, projectileValue, finalEntityDamage, attackerEntity, null, equipmentTags | _attackDetails.WeaponTypeTag | hitEntityAlive.EntityClass.Tags, true, false); + finalEntityDamage = (int)MultiActionReversePatches.ProjectileGetValue(PassiveEffects.InternalDamageModifier, projectileValue, finalEntityDamage, hitEntityAlive, null, equipmentTags | projectileValue.ItemClass.ItemTags, true, false); + } + if (!hitEntityAlive || hitEntityAlive.Health > 0) + { + finalEntityDamage = Utils.FastMax(1, ItemActionAttack.difficultyModifier(finalEntityDamage, world.GetEntity(_attackerEntityId), hitEntity)); + } + else if (_toolBonuses != null) + { + finalEntityDamage = (int)(finalEntityDamage * calculateHarvestToolDamageBonus(_toolBonuses, EntityClass.list[hitEntity.entityClass].itemsToDrop)); + } + //Log.Out("Final entity damage: " + finalEntityDamage); + bool isAlreadyDead = hitEntity.IsDead(); + int deathHealth = (hitEntityAlive != null) ? hitEntityAlive.DeathHealth : 0; + if (_attackMode != ItemActionAttack.EnumAttackMode.Simulate) + { + if (attackerEntity != null) + { + MinEventParams minEventContext = attackerEntity.MinEventContext; + minEventContext.Other = hitEntityAlive; + minEventContext.StartPosition = hitInfo.ray.origin; + } + if (SingletonMonoBehaviour.Instance.IsServer && (attackerEntity as EntityPlayer == null || !attackerEntity.isEntityRemote) && hitEntity.isEntityRemote && rangeCheckedAction != null) + { + EntityPlayer hitPlayer = hitEntity as EntityPlayer; + if (hitPlayer != null) + { + isHitTargetPlayer = false; + Ray lookRay = attackerEntity.GetLookRay(); + lookRay.origin -= lookRay.direction * 0.15f; + float range = Utils.FastMax(rangeCheckedAction.Range, rangeCheckedAction.BlockRange) * ItemActionAttack.attackRangeMultiplier; + string hitTransformPath = null; + List list_buffs = _buffActions; + if (list_buffs != null) + { + if (hitEntityAlive) + { + hitTransformPath = (hitBodyPart != null) ? GameUtils.GetChildTransformPath(hitEntity.transform, hitInfo.transform) : null; + } + else + { + list_buffs = null; + } + } + if (attackerEntity != null) + { + attackerEntity.FireEvent(MinEventTypes.onSelfAttackedOther, isHoldingDamageItem); + if (hitEntityAlive != null && hitEntityAlive.RecordedDamage.Strength > 0) + { + attackerEntity.FireEvent(MinEventTypes.onSelfDamagedOther, isHoldingDamageItem); + } + } + if (!isAlreadyDead && hitEntity.IsDead() && attackerEntity != null) + { + attackerEntity.FireEvent(MinEventTypes.onSelfKilledOther, isHoldingDamageItem); + } + if (hitEntityAlive && hitEntityAlive.RecordedDamage.ArmorDamage > hitEntityAlive.RecordedDamage.Strength) + { + surfaceCategory = "metal"; + } + else + { + surfaceCategory = EntityClass.list[hitEntity.entityClass].Properties.Values["SurfaceCategory"]; + } + blockFaceParticle = surfaceCategory; + lightValueAtBlockPos = hitEntity.GetLightBrightness(); + string hitParticle = string.Format("impact_{0}_on_{1}", _attackingDeviceMadeOf, blockFaceParticle); + string hitSound = (surfaceCategory != null) ? string.Format("{0}hit{1}", _attackingDeviceMadeOf, surfaceCategory) : null; + if (_hitSoundOverrides != null && _hitSoundOverrides.ContainsKey(surfaceCategory)) + { + hitSound = _hitSoundOverrides[surfaceCategory]; + } + ParticleEffect particleEffect2 = new ParticleEffect(hitParticle, hitInfo.fmcHit.pos, Utils.BlockFaceToRotation(hitInfo.fmcHit.blockFace), lightValueAtBlockPos, blockFaceColor, hitSound, null); + hitPlayer.ServerNetSendRangeCheckedDamage(lookRay.origin, range, damageSourceEntity, finalEntityDamage, isCriticalHit, list_buffs, hitTransformPath, particleEffect2); + } + } + if (isHitTargetPlayer) + { + int damageDealt = hitEntity.DamageEntity(damageSourceEntity, finalEntityDamage, isCriticalHit, 1f); + if (damageDealt != -1 && attackerEntity) + { + MinEventParams attackerMinEventParams = attackerEntity.MinEventContext; + attackerMinEventParams.Other = hitEntityAlive; + attackerMinEventParams.StartPosition = hitInfo.ray.origin; + if (ownedEntityId != -1) + { + launcherValue.FireEvent(MinEventTypes.onSelfAttackedOther, attackerEntity.MinEventContext); + } + attackerEntity.FireEvent(MinEventTypes.onSelfAttackedOther, isHoldingDamageItem); + if (hitEntityAlive && hitEntityAlive.RecordedDamage.Strength > 0) + { + attackerEntity.FireEvent(MinEventTypes.onSelfDamagedOther, isHoldingDamageItem); + } + } + if (!isAlreadyDead && hitEntity.IsDead() && attackerEntity) + { + attackerEntity.FireEvent(MinEventTypes.onSelfKilledOther, isHoldingDamageItem); + } + if (damageDealt != -1 && hitEntityAlive && _buffActions != null && _buffActions.Count > 0) + { + for (int i = 0; i < _buffActions.Count; i++) + { + BuffClass buff = BuffManager.GetBuff(_buffActions[i]); + if (buff != null) + { + float bufProcChance = MultiActionReversePatches.ProjectileGetValue(PassiveEffects.BuffProcChance, null, 1f, attackerEntity, null, FastTags.Parse(buff.Name), true, false); + if (hitEntityAlive.rand.RandomFloat <= bufProcChance) + { + hitEntityAlive.Buffs.AddBuff(_buffActions[i], attackerEntity.entityId, true, false, -1f); + } + } + } + } + } + } + if (hitEntityAlive && hitEntityAlive.RecordedDamage.ArmorDamage > hitEntityAlive.RecordedDamage.Strength) + { + surfaceCategory = "metal"; + } + else + { + surfaceCategory = EntityClass.list[hitEntity.entityClass].Properties.Values["SurfaceCategory"]; + } + blockFaceParticle = surfaceCategory; + lightValueAtBlockPos = hitEntity.GetLightBrightness(); + EntityPlayer attackerPlayer = attackerEntity as EntityPlayer; + if (attackerPlayer) + { + if (isAlreadyDead && hitEntity.IsDead() && hitEntityAlive && hitEntityAlive.DeathHealth + finalEntityDamage > -1 * EntityClass.list[hitEntity.entityClass].DeadBodyHitPoints) + { + _attackDetails.damageTotalOfTarget = (float)(-1 * hitEntityAlive.DeathHealth); + _attackDetails.damageGiven = deathHealth + Mathf.Min(EntityClass.list[hitEntity.entityClass].DeadBodyHitPoints, Mathf.Abs(hitEntityAlive.DeathHealth)); + _attackDetails.damageMax = EntityClass.list[hitEntity.entityClass].DeadBodyHitPoints; + _attackDetails.bKilled = -1 * hitEntityAlive.DeathHealth >= EntityClass.list[hitEntity.entityClass].DeadBodyHitPoints; + _attackDetails.itemsToDrop = EntityClass.list[hitEntity.entityClass].itemsToDrop; + _attackDetails.entityHit = hitEntity; + _attackDetails.materialCategory = surfaceCategory; + } + if (!isAlreadyDead && (hitEntityAlive.IsDead() || hitEntityAlive.Health <= 0) && EntityClass.list.ContainsKey(hitEntity.entityClass)) + { + if ((_flags & 2) > 0) + { + float trapXP = MultiActionReversePatches.ProjectileGetValue(PassiveEffects.ElectricalTrapXP, attackerPlayer.inventory.holdingItemItemValue, 0f, attackerPlayer, null, default, true, false); + if (trapXP > 0f) + { + attackerPlayer.AddKillXP(hitEntityAlive, trapXP); + } + } + else + { + attackerPlayer.AddKillXP(hitEntityAlive, 1f); + } + } + } + if (hitEntity is EntityDrone) + { + _attackDetails.entityHit = hitEntity; + } + } + if ((_flags & 8) > 0) + { + canHarvest = false; + } + if (isHitTargetPlayer && _attackMode != ItemActionAttack.EnumAttackMode.Simulate && canHarvest && blockFaceParticle != null && ((_attackDetails.bBlockHit && !_attackDetails.bKilled) || !_attackDetails.bBlockHit)) + { + string hitParticle = string.Format("impact_{0}_on_{1}", _attackingDeviceMadeOf, blockFaceParticle); + if (_attackMode == ItemActionAttack.EnumAttackMode.RealAndHarvesting && (_flags & 4) > 0 && ParticleEffect.IsAvailable(hitParticle + "_harvest")) + { + hitParticle += "_harvest"; + } + string hitSound = (surfaceCategory != null) ? string.Format("{0}hit{1}", _attackingDeviceMadeOf, surfaceCategory) : null; + if (_hitSoundOverrides != null && _hitSoundOverrides.ContainsKey(surfaceCategory)) + { + hitSound = _hitSoundOverrides[surfaceCategory]; + } + world.GetGameManager().SpawnParticleEffectServer(new ParticleEffect(hitParticle, hitInfo.fmcHit.pos, Utils.BlockFaceToRotation(hitInfo.fmcHit.blockFace), lightValueAtBlockPos, blockFaceColor, hitSound, null), _attackerEntityId, false, true); + } + if ((_flags & 1) > 0 && attackerEntity != null && attackerEntity.inventory != null) + { + attackerEntity.inventory.CallOnToolbeltChangedInternal(); + } + } + + private static float calculateHarvestToolDamageBonus(Dictionary _toolBonuses, Dictionary> _harvestItems) + { + if (!_harvestItems.ContainsKey(EnumDropEvent.Harvest)) + { + return 1f; + } + List list = _harvestItems[EnumDropEvent.Harvest]; + for (int i = 0; i < list.Count; i++) + { + if (list[i].toolCategory != null && _toolBonuses.ContainsKey(list[i].toolCategory)) + { + return _toolBonuses[list[i].toolCategory].Damage; + } + } + return 1f; + } + + public static float GetProjectileDamageBlock(this ItemActionAttack self, ItemValue _itemValue, BlockValue _blockValue, EntityAlive _holdingEntity = null, int actionIndex = 0) + { + FastTags tmpTag = ((actionIndex != 1) ? ItemActionAttack.PrimaryTag : ItemActionAttack.SecondaryTag); + ItemClass launcherClass = ItemClass.GetForId(_itemValue.Meta); + tmpTag |= ((launcherClass == null) ? ItemActionAttack.MeleeTag : launcherClass.ItemTags); + if (_holdingEntity != null) + { + tmpTag |= _holdingEntity.CurrentStanceTag | _holdingEntity.CurrentMovementTag; + } + + tmpTag |= _blockValue.Block.Tags; + float value = MultiActionReversePatches.ProjectileGetValue(PassiveEffects.BlockDamage, _itemValue, self.damageBlock, _holdingEntity, null, tmpTag, true, false)/* * GetProjectileBlockDamagePerc(_itemValue, _holdingEntity)*/; + //Log.Out($"block damage {value} base damage {self.GetBaseDamageBlock(null)} action index {actionIndex} launcher {launcherClass.Name} projectile {_itemValue.ItemClass.Name}"); + return value; + } + + public static float GetProjectileDamageEntity(this ItemActionAttack self, ItemValue _itemValue, EntityAlive _holdingEntity = null, int actionIndex = 0) + { + FastTags tmpTag = ((actionIndex != 1) ? ItemActionAttack.PrimaryTag : ItemActionAttack.SecondaryTag); + ItemClass launcherClass = ItemClass.GetForId(_itemValue.Meta); + tmpTag |= ((launcherClass == null) ? ItemActionAttack.MeleeTag : launcherClass.ItemTags); + if (_holdingEntity != null) + { + tmpTag |= _holdingEntity.CurrentStanceTag | _holdingEntity.CurrentMovementTag; + } + + var res = MultiActionReversePatches.ProjectileGetValue(PassiveEffects.EntityDamage, _itemValue, self.damageEntity, _holdingEntity, null, tmpTag, true, false)/* * GetProjectileEntityDamagePerc(_itemValue, _holdingEntity)*/; +#if DEBUG + Log.Out($"get projectile damage entity for action index {actionIndex}, item {launcherClass.Name}, result {res}"); +#endif + return res; + } + + //public static float GetProjectileBlockDamagePerc(ItemValue _itemValue, EntityAlive _holdingEntity) + //{ + // float value = MultiActionReversePatches.ProjectileGetValue(CustomEnums.ProjectileImpactDamagePercentBlock, _itemValue, 1, _holdingEntity, null); + // //Log.Out("Block damage perc: " + value); + // return value; + //} + + //public static float GetProjectileEntityDamagePerc(ItemValue _itemValue, EntityAlive _holdingEntity) + //{ + // float value = MultiActionReversePatches.ProjectileGetValue(CustomEnums.ProjectileImpactDamagePercentEntity, _itemValue, 1, _holdingEntity, null); + // //Log.Out("Entity damage perc: " + value); + // return value; + //} + + public static void ProjectileValueModifyValue(this ItemValue _projectileItemValue, EntityAlive _entity, ItemValue _originalItemValue, PassiveEffects _passiveEffect, ref float _originalValue, ref float _perc_value, FastTags _tags, bool _useMods = true, bool _useDurability = false) + { + if (_originalItemValue != null) + { + Log.Warning($"original item value present: item {_originalItemValue.ItemClass.Name}"); + return; + } + int seed = MinEventParams.CachedEventParam.Seed; + if (_entity != null) + { + seed = _entity.MinEventContext.Seed; + } + + ItemClass launcherClass = ItemClass.GetForId(_projectileItemValue.Meta); + int actionIndex = _projectileItemValue.SelectedAmmoTypeIndex; + if (launcherClass != null) + { + if (launcherClass.Actions != null && launcherClass.Actions.Length != 0 && launcherClass.Actions[actionIndex] is ItemActionRanged) + { + ItemClass ammoClass = _projectileItemValue.ItemClass; + if (ammoClass != null && ammoClass.Effects != null) + { + ammoClass.Effects.ModifyValue(_entity, _passiveEffect, ref _originalValue, ref _perc_value, 0f, _tags); + } + } + + if (launcherClass.Effects != null) + { + MinEventParams.CachedEventParam.Seed = (int)_projectileItemValue.Seed + (int)((_projectileItemValue.Seed != 0) ? _passiveEffect : PassiveEffects.None); + if (_entity != null) + { + _entity.MinEventContext.Seed = MinEventParams.CachedEventParam.Seed; + } + + float prevOriginal = _originalValue; + launcherClass.Effects.ModifyValue(_entity, _passiveEffect, ref _originalValue, ref _perc_value, _projectileItemValue.Quality, _tags); + if (_useDurability) + { + float percentUsesLeft = _projectileItemValue.PercentUsesLeft; + switch (_passiveEffect) + { + case PassiveEffects.PhysicalDamageResist: + if (percentUsesLeft < 0.5f) + { + float diff = _originalValue - prevOriginal; + _originalValue = prevOriginal + diff * percentUsesLeft * 2f; + } + + break; + case PassiveEffects.ElementalDamageResist: + if (percentUsesLeft < 0.5f) + { + float diff = _originalValue - prevOriginal; + _originalValue = prevOriginal + diff * percentUsesLeft * 2f; + } + + break; + case PassiveEffects.BuffResistance: + if (percentUsesLeft < 0.5f) + { + float diff = _originalValue - prevOriginal; + _originalValue = prevOriginal + diff * percentUsesLeft * 2f; + } + + break; + } + } + } + } + else + { + Log.Warning($"launcher class not found: item id{_projectileItemValue.Meta}"); + } + + if (_useMods) + { + for (int i = 0; i < _projectileItemValue.CosmeticMods.Length; i++) + { + if (_projectileItemValue.CosmeticMods[i] != null && _projectileItemValue.CosmeticMods[i].ItemClass is ItemClassModifier && !MultiActionManager.ShouldExcludePassive(_projectileItemValue.type, _projectileItemValue.CosmeticMods[i].type, actionIndex)) + { + _projectileItemValue.CosmeticMods[i].ModifyValue(_entity, _projectileItemValue, _passiveEffect, ref _originalValue, ref _perc_value, _tags); + } + } + + for (int i = 0; i < _projectileItemValue.Modifications.Length; i++) + { + if (_projectileItemValue.Modifications[i] != null && _projectileItemValue.Modifications[i].ItemClass is ItemClassModifier && !MultiActionManager.ShouldExcludePassive(_projectileItemValue.type, _projectileItemValue.Modifications[i].type, actionIndex)) + { + _projectileItemValue.Modifications[i].ModifyValue(_entity, _projectileItemValue, _passiveEffect, ref _originalValue, ref _perc_value, _tags); + } + } + } + } + } +} \ No newline at end of file diff --git a/Scripts/Utilities/MultiActionUtils.cs b/Scripts/Utilities/MultiActionUtils.cs new file mode 100644 index 0000000..d69020d --- /dev/null +++ b/Scripts/Utilities/MultiActionUtils.cs @@ -0,0 +1,445 @@ +using KFCommonUtilityLib.Scripts.StaticManagers; +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace KFCommonUtilityLib.Scripts.Utilities +{ + public static class MultiActionUtils + { + public static readonly string[] ActionMetaNames = new string[] + { + "Meta0", + "Meta1", + "Meta2", + "Meta3", + "Meta4", + }; + public static readonly string[] ActionSelectedAmmoNames = new string[] + { + "AmmoIndex0", + "AmmoIndex1", + "AmmoIndex2", + "AmmoIndex3", + "AmmoIndex4", + }; + public static readonly int ExecutingActionIndexHash = Animator.StringToHash("ExecutingActionIndex"); + + public static void SetMinEventArrays() + { + MinEvent.Start = new[] + { + MinEventTypes.onSelfPrimaryActionStart, + MinEventTypes.onSelfSecondaryActionStart, + MinEventTypes.onSelfAction2Start, + MinEventTypes.onSelfPrimaryActionStart, + MinEventTypes.onSelfPrimaryActionStart, + }; + + MinEvent.Update = new[] + { + MinEventTypes.onSelfPrimaryActionUpdate, + MinEventTypes.onSelfSecondaryActionUpdate, + MinEventTypes.onSelfAction2Update, + MinEventTypes.onSelfPrimaryActionUpdate, + MinEventTypes.onSelfPrimaryActionUpdate, + }; + + MinEvent.End = new[] + { + MinEventTypes.onSelfPrimaryActionEnd, + MinEventTypes.onSelfSecondaryActionEnd, + MinEventTypes.onSelfAction2End, + MinEventTypes.onSelfPrimaryActionEnd, + MinEventTypes.onSelfPrimaryActionEnd, + }; + } + + //public static int GetActionIndexForItemValue(this ItemValue self) + //{ + // object val = self.GetMetadata(MultiActionMapping.STR_MULTI_ACTION_INDEX); + // if (val is int index) + // return index; + // return 0; + //} + + public static string GetPropertyName(int index, string prop) + { + return $"Action{index}.{prop}"; + } + + public static void FixedItemReloadServer(int entityId, int actionIndex) + { + if (GameManager.Instance.World == null) + { + return; + } + + FixedItemReloadClient(entityId, actionIndex); + + if (!SingletonMonoBehaviour.Instance.IsServer) + { + SingletonMonoBehaviour.Instance.SendToServer(NetPackageManager.GetPackage().Setup(entityId, actionIndex), false); + return; + } + SingletonMonoBehaviour.Instance.SendPackage(NetPackageManager.GetPackage().Setup(entityId, actionIndex), false, -1, entityId); + } + + public static void FixedItemReloadClient(int entityId, int actionIndex) + { + if (GameManager.Instance.World == null) + { + return; + } + EntityAlive entityAlive = (EntityAlive)GameManager.Instance.World.GetEntity(entityId); + if (entityAlive != null && entityAlive.inventory.holdingItem.Actions[actionIndex] is ItemActionRanged actionRanged) + { + entityAlive.MinEventContext.ItemActionData = entityAlive.inventory.holdingItemData.actionData[actionIndex]; + actionRanged.ReloadGun(entityAlive.inventory.holdingItemData.actionData[actionIndex]); + } + } + + public static void CopyLauncherValueToProjectile(ItemValue launcherValue, ItemValue projectileValue, int index) + { + projectileValue.Meta = launcherValue.type; + projectileValue.SelectedAmmoTypeIndex = (byte)index; + projectileValue.UseTimes = launcherValue.UseTimes; + projectileValue.Quality = launcherValue.Quality; + projectileValue.Modifications = new ItemValue[launcherValue.Modifications.Length]; + Array.Copy(launcherValue.Modifications, projectileValue.Modifications, launcherValue.Modifications.Length); + projectileValue.CosmeticMods = new ItemValue[launcherValue.CosmeticMods.Length]; + Array.Copy(launcherValue.CosmeticMods, projectileValue.CosmeticMods, launcherValue.CosmeticMods.Length); + } + + public static void SetMinEventParamsActionData(EntityAlive entity, int actionIndex) + { + if (actionIndex >= 0 && actionIndex < entity.inventory?.holdingItemData?.actionData?.Count) + entity.MinEventContext.ItemActionData = entity.inventory.holdingItemData.actionData[actionIndex]; + } + + public static string GetPropertyOverrideForAction(this ItemValue self, string _propertyName, string _originalValue, int actionIndex) + { + if (self.Modifications.Length == 0 && self.CosmeticMods.Length == 0) + { + return _originalValue; + } + string text = ""; + ItemClass item = self.ItemClass; + for (int i = 0; i < self.Modifications.Length; i++) + { + ItemValue itemValue = self.Modifications[i]; + if (itemValue != null) + { + if (itemValue.ItemClass is ItemClassModifier mod && GetPropertyOverrideForMod(mod, _propertyName, item, ref text, actionIndex)) + { + return text; + } + } + } + text = ""; + for (int j = 0; j < self.CosmeticMods.Length; j++) + { + ItemValue itemValue2 = self.CosmeticMods[j]; + if (itemValue2 != null) + { + if (itemValue2.ItemClass is ItemClassModifier cos && GetPropertyOverrideForMod(cos, _propertyName, item, ref text, actionIndex)) + { + return text; + } + } + } + return _originalValue; + } + + public static IEnumerable GetAllPropertyOverridesForAction(this ItemValue self, string _propertyName, int actionIndex) + { + if (self.Modifications.Length == 0 && self.CosmeticMods.Length == 0) + { + yield break; + } + + string text = ""; + ItemClass item = self.ItemClass; + for (int i = 0; i < self.Modifications.Length; i++) + { + ItemValue itemValue = self.Modifications[i]; + if (itemValue != null) + { + if (itemValue.ItemClass is ItemClassModifier mod && GetPropertyOverrideForMod(mod, _propertyName, item, ref text, actionIndex)) + { + yield return text; + } + } + } + text = ""; + for (int j = 0; j < self.CosmeticMods.Length; j++) + { + ItemValue itemValue2 = self.CosmeticMods[j]; + if (itemValue2 != null) + { + if (itemValue2.ItemClass is ItemClassModifier cos && GetPropertyOverrideForMod(cos, _propertyName, item, ref text, actionIndex)) + { + yield return text; + } + } + } + } + + public static bool GetPropertyOverrideForMod(ItemClassModifier mod, string _propertyName, ItemClass _item, ref string _value, int actionIndex) + { + //Log.Out($"Get property override for item {_item.Name} itemID{_item.Id} property {_propertyName} mod {mod.Name} modID {mod.Id} action {actionIndex} should exclude {MultiActionManager.ShouldExcludeMod(_item.Id, mod.Id, actionIndex)}"); + if (MultiActionManager.ShouldExcludeProperty(_item.Id, mod.Id, actionIndex)) + return false; + string _itemName = _item.GetItemName(); + string itemNameWithActionIndex = $"{_itemName}_{actionIndex}"; + if (mod.PropertyOverrides.ContainsKey(itemNameWithActionIndex) && mod.PropertyOverrides[itemNameWithActionIndex].Values.ContainsKey(_propertyName)) + { + _value = mod.PropertyOverrides[itemNameWithActionIndex].Values[_propertyName]; + return true; + } + if (mod.PropertyOverrides.ContainsKey(_itemName) && mod.PropertyOverrides[_itemName].Values.ContainsKey(_propertyName)) + { + _value = mod.PropertyOverrides[_itemName].Values[_propertyName]; + return true; + } + itemNameWithActionIndex = $"*_{actionIndex}"; + if (mod.PropertyOverrides.ContainsKey(itemNameWithActionIndex) && mod.PropertyOverrides[itemNameWithActionIndex].Values.ContainsKey(_propertyName)) + { + _value = mod.PropertyOverrides[itemNameWithActionIndex].Values[_propertyName]; + return true; + } + if (mod.PropertyOverrides.ContainsKey("*") && mod.PropertyOverrides["*"].Values.ContainsKey(_propertyName)) + { + _value = mod.PropertyOverrides["*"].Values[_propertyName]; + return true; + } + return false; + } + + public static int GetMode(this ItemValue self) + { + object mode = self.GetMetadata(MultiActionMapping.STR_MULTI_ACTION_INDEX); + if (mode is int v) + { + return v; + } + return 0; + } + + public static int GetActionIndexByEntityEventParams(EntityAlive entity) + { + return GetActionIndexByEventParams(entity?.MinEventContext ?? MinEventParams.CachedEventParam); + } + + public static int GetActionIndexByEventParams(MinEventParams pars) + { + if (pars?.ItemActionData == null) + return 0; + return pars.ItemActionData.indexInEntityOfAction; + } + + public static int GetActionIndexByMetaData(this ItemValue self) + { + int mode = self.GetMode(); + MultiActionIndice indice = MultiActionManager.GetActionIndiceForItemID(self.type); + return indice.GetActionIndexForMode(mode); + } + + public static int GetSelectedAmmoIndexByMode(this ItemValue self, int mode) + { + MultiActionIndice indice = MultiActionManager.GetActionIndiceForItemID(self.type); + int metaIndex = indice.GetMetaIndexForMode(mode); + if (metaIndex >= 0) + { + object ammoIndex = self.GetMetadata(ActionSelectedAmmoNames[metaIndex]); + if (ammoIndex is int) + { + return (int)ammoIndex; + } + } + return self.SelectedAmmoTypeIndex; + } + + public static int GetMetaByMode(this ItemValue self, int mode) + { + MultiActionIndice indice = MultiActionManager.GetActionIndiceForItemID(self.type); + int metaIndex = indice.GetMetaIndexForMode(mode); + if (metaIndex >= 0) + { + object meta = self.GetMetadata(ActionMetaNames[metaIndex]); + if (meta is int) + { + return (int)meta; + } + } + return self.Meta; + } + + public static int GetSelectedAmmoIndexByActionIndex(this ItemValue self, int actionIndex) + { + MultiActionIndice indice = MultiActionManager.GetActionIndiceForItemID(self.type); + int mode = indice.GetModeForAction(actionIndex); + if (mode < 0) + return self.SelectedAmmoTypeIndex; + int metaIndex = indice.GetMetaIndexForMode(mode); + if (metaIndex >= 0) + { + object ammoIndex = self.GetMetadata(ActionSelectedAmmoNames[metaIndex]); + if (ammoIndex is int) + { + return (int)ammoIndex; + } + } + return self.SelectedAmmoTypeIndex; + } + + public static int GetMetaByActionIndex(this ItemValue self, int actionIndex) + { + MultiActionIndice indice = MultiActionManager.GetActionIndiceForItemID(self.type); + int mode = indice.GetModeForAction(actionIndex); + if (mode < 0) + return self.Meta; + int metaIndex = indice.GetMetaIndexForMode(mode); + if (metaIndex >= 0) + { + object meta = self.GetMetadata(ActionMetaNames[metaIndex]); + if (meta is int) + { + //Log.Out($"GetMetaByActionIndex: mode: {mode}, action: {metaIndex}, meta: {(int)meta}\n{StackTraceUtility.ExtractStackTrace()}"); + return (int)meta; + } + } + + return self.Meta; + } + + public static void SetMinEventParamsByEntityInventory(EntityAlive entity) + { + if (entity != null && entity.MinEventContext != null) + { + entity.MinEventContext.ItemActionData = entity.inventory?.holdingItemData?.actionData[MultiActionManager.GetActionIndexForEntity(entity)]; + } + } + + public static bool MultiActionRemoveAmmoFromItemStack(ItemStack stack, List result) + { + ItemValue itemValue = stack.itemValue; + object mode = itemValue.GetMetadata(MultiActionMapping.STR_MULTI_ACTION_INDEX); + if (mode is false || mode is null) + { + return false; + } + MultiActionIndice indices = MultiActionManager.GetActionIndiceForItemID(itemValue.type); + ItemClass item = ItemClass.GetForId(itemValue.type); + for (int i = 0; i < MultiActionIndice.MAX_ACTION_COUNT; i++) + { + int metaIndex = indices.GetMetaIndexForMode(i); + if (metaIndex < 0) + { + break; + } + + int actionIndex = indices.GetActionIndexForMode(i); + if (item.Actions[actionIndex] is ItemActionRanged ranged && !(ranged is ItemActionTextureBlock)) + { + object meta = itemValue.GetMetadata(MultiActionUtils.ActionMetaNames[metaIndex]); + object ammoIndex = itemValue.GetMetadata(MultiActionUtils.ActionSelectedAmmoNames[metaIndex]); + if (meta is int && ammoIndex is int && (int)meta > 0) + { + itemValue.SetMetadata(MultiActionUtils.ActionMetaNames[metaIndex], 0, TypedMetadataValue.TypeTag.Integer); + ItemStack ammoStack = new ItemStack(ItemClass.GetItem(ranged.MagazineItemNames[(int)ammoIndex]), (int)meta); + result.Add(ammoStack); + Log.Out($"Remove ammo: metadata {MultiActionUtils.ActionMetaNames[metaIndex]}, meta {(int)meta}, left {itemValue.GetMetadata(MultiActionUtils.ActionMetaNames[metaIndex])}"); + } + } + } + itemValue.Meta = 0; + return true; + } + + public static readonly ItemActionData[] DummyActionDatas = new ItemActionData[] + { + new ItemActionData(null, 0), + new ItemActionData(null, 3), + new ItemActionData(null, 4) + }; + + public static int GetMultiActionInitialMetaData(this ItemClass itemClass, ItemValue itemValue) + { + MultiActionIndice indice = MultiActionManager.GetActionIndiceForItemID(itemClass.Id); + if (indice.modeCount <= 1) + { + return itemClass.GetInitialMetadata(itemValue); + } + + var prevItemValue = MinEventParams.CachedEventParam.ItemValue; + var prevActionData = MinEventParams.CachedEventParam.ItemActionData; + MinEventParams.CachedEventParam.ItemValue = itemValue; + itemValue.SetMetadata(MultiActionMapping.STR_MULTI_ACTION_INDEX, 0, TypedMetadataValue.TypeTag.Integer); + int ret = 0; + for (int i = 0; i < indice.modeCount; i++) + { + MinEventParams.CachedEventParam.ItemActionData = DummyActionDatas[i]; + + ItemAction itemAction = itemClass.Actions[indice.GetActionIndexForMode(i)]; + int meta = itemAction.GetInitialMeta(itemValue); + if (i == 0) + { + ret = meta; + } + else if (itemAction.Properties.Contains("ActionUnlocked") && !itemAction.Properties.GetBool("ActionUnlocked")) + { + meta = 0; + } + if (indice.GetMetaIndexForMode(i) == indice.GetActionIndexForMode(i)) + itemValue.SetMetadata(MultiActionUtils.ActionMetaNames[indice.GetMetaIndexForMode(i)], meta, TypedMetadataValue.TypeTag.Integer); + } + MinEventParams.CachedEventParam.ItemValue = prevItemValue; + MinEventParams.CachedEventParam.ItemActionData = prevActionData; + return ret; + } + + public static void SetCachedEventParamsDummyAction(ItemStack itemStack) + { + ItemClass itemClass = itemStack?.itemValue?.ItemClass; + if (itemClass != null) + { + MinEventParams.CachedEventParam.ItemActionData = MultiActionUtils.DummyActionDatas[itemStack.itemValue.GetMode()]; + MinEventParams.CachedEventParam.ItemValue = itemStack.itemValue; + MinEventParams.CachedEventParam.Seed = itemStack.itemValue.Seed; + } + } + + public static string GetDisplayTypeForAction(ItemStack itemStack) + { + return GetDisplayTypeForAction(itemStack?.itemValue); + } + + public static string GetDisplayTypeForAction(ItemValue itemValue) + { + if (itemValue == null || itemValue.IsEmpty()) + { + return ""; + } + if (itemValue.ItemClass.Actions[itemValue.GetActionIndexByMetaData()] is IModuleContainerFor module) + { + return module.Instance.GetDisplayType(itemValue); + } + return itemValue.ItemClass.DisplayType; + } + + public static bool CanCompare(ItemValue itemValue1, ItemValue itemValue2) + { + if (itemValue1 == null || itemValue2 == null || itemValue1.IsEmpty() || itemValue2.IsEmpty()) + { + return false; + } + + string displayType1 = itemValue1.ItemClass.IsBlock() ? Block.list[itemValue1.ItemClass.Id].DisplayType : GetDisplayTypeForAction(itemValue1); + string displayType2 = itemValue2.ItemClass.IsBlock() ? Block.list[itemValue2.ItemClass.Id].DisplayType : GetDisplayTypeForAction(itemValue2); + ItemDisplayEntry displayStatsForTag = UIDisplayInfoManager.Current.GetDisplayStatsForTag(displayType1); + ItemDisplayEntry displayStatsForTag2 = UIDisplayInfoManager.Current.GetDisplayStatsForTag(displayType2); + return displayStatsForTag != null && displayStatsForTag2 != null && displayStatsForTag.DisplayGroup == displayStatsForTag2.DisplayGroup; + } + } +} \ No newline at end of file diff --git a/Scripts/Utilities/SaveTextureToFileUtility.cs b/Scripts/Utilities/SaveTextureToFileUtility.cs new file mode 100644 index 0000000..d4aef81 --- /dev/null +++ b/Scripts/Utilities/SaveTextureToFileUtility.cs @@ -0,0 +1,134 @@ +using Unity.Collections; +using UnityEngine; +using UnityEngine.Rendering; + +public class SaveTextureToFileUtility +{ + public enum SaveTextureFileFormat + { + EXR, JPG, PNG, TGA + }; + + /// + /// Saves a Texture2D to disk with the specified filename and image format + /// + /// + /// + /// + /// + static public void SaveTexture2DToFile(Texture2D tex, string filePath, SaveTextureFileFormat fileFormat, int jpgQuality = 95) + { + switch (fileFormat) + { + case SaveTextureFileFormat.EXR: + System.IO.File.WriteAllBytes(filePath + ".exr", tex.EncodeToEXR()); + break; + case SaveTextureFileFormat.JPG: + System.IO.File.WriteAllBytes(filePath + ".jpg", tex.EncodeToJPG(jpgQuality)); + break; + case SaveTextureFileFormat.PNG: + System.IO.File.WriteAllBytes(filePath + ".png", tex.EncodeToPNG()); + break; + case SaveTextureFileFormat.TGA: + System.IO.File.WriteAllBytes(filePath + ".tga", tex.EncodeToTGA()); + break; + } + } + + + /// + /// Saves a RenderTexture to disk with the specified filename and image format + /// + /// + /// + /// + /// + static public void SaveRenderTextureToFile(RenderTexture renderTexture, string filePath, SaveTextureFileFormat fileFormat = SaveTextureFileFormat.PNG, int jpgQuality = 95) + { + Texture2D tex; + if (fileFormat != SaveTextureFileFormat.EXR) + tex = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false, false); + else + tex = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.RGBAFloat, false, true); + var oldRt = RenderTexture.active; + RenderTexture.active = renderTexture; + tex.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0); + tex.Apply(); + RenderTexture.active = oldRt; + SaveTexture2DToFile(tex, filePath, fileFormat, jpgQuality); + if (Application.isPlaying) + Object.Destroy(tex); + else + Object.DestroyImmediate(tex); + + } + + static public void SaveTextureToFile(Texture source, + string filePath, + int width, + int height, + SaveTextureFileFormat fileFormat = SaveTextureFileFormat.PNG, + int jpgQuality = 95, + bool asynchronous = true, + System.Action done = null) + { + // check that the input we're getting is something we can handle: + if (!(source is Texture2D || source is RenderTexture)) + { + done?.Invoke(false); + return; + } + + // use the original texture size in case the input is negative: + if (width < 0 || height < 0) + { + width = source.width; + height = source.height; + } + + // resize the original image: + var resizeRT = RenderTexture.GetTemporary(width, height, 0); + Graphics.Blit(source, resizeRT); + + // create a native array to receive data from the GPU: + var narray = new NativeArray(width * height * 4, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); + + // request the texture data back from the GPU: + var request = AsyncGPUReadback.RequestIntoNativeArray(ref narray, resizeRT, 0, (AsyncGPUReadbackRequest req) => + { + // if the readback was successful, encode and write the results to disk + if (!req.hasError) + { + NativeArray encoded; + + switch (fileFormat) + { + case SaveTextureFileFormat.EXR: + encoded = ImageConversion.EncodeNativeArrayToEXR(narray, resizeRT.graphicsFormat, (uint)width, (uint)height); + break; + case SaveTextureFileFormat.JPG: + encoded = ImageConversion.EncodeNativeArrayToJPG(narray, resizeRT.graphicsFormat, (uint)width, (uint)height, 0, jpgQuality); + break; + case SaveTextureFileFormat.TGA: + encoded = ImageConversion.EncodeNativeArrayToTGA(narray, resizeRT.graphicsFormat, (uint)width, (uint)height); + break; + default: + encoded = ImageConversion.EncodeNativeArrayToPNG(narray, resizeRT.graphicsFormat, (uint)width, (uint)height); + break; + } + + System.IO.File.WriteAllBytes(filePath, encoded.ToArray()); + encoded.Dispose(); + } + + narray.Dispose(); + + // notify the user that the operation is done, and its outcome. + done?.Invoke(!req.hasError); + }); + + if (!asynchronous) + request.WaitForCompletion(); + } + +} \ No newline at end of file diff --git a/Scripts/Utilities/TemporaryMuzzleFlash.cs b/Scripts/Utilities/TemporaryMuzzleFlash.cs new file mode 100644 index 0000000..b457650 --- /dev/null +++ b/Scripts/Utilities/TemporaryMuzzleFlash.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace KFCommonUtilityLib +{ + public class TemporaryMuzzleFlash : TemporaryObject + { + private void OnDisable() + { + StopAllCoroutines(); + if (destroyMaterials) + { + Utils.CleanupMaterialsOfRenderers(transform.GetComponentsInChildren()); + } + Destroy(gameObject); + } + } +} diff --git a/Scripts/Utilities/TypeBasedUID.cs b/Scripts/Utilities/TypeBasedUID.cs new file mode 100644 index 0000000..4ddb061 --- /dev/null +++ b/Scripts/Utilities/TypeBasedUID.cs @@ -0,0 +1,5 @@ +public class TypeBasedUID +{ + private static int uid = 0; + public static int UID { get => uid++; } +} \ No newline at end of file diff --git a/TreeCollections.dll b/TreeCollections.dll new file mode 100644 index 0000000000000000000000000000000000000000..a2d5f1bc8b1ab87306ef681d1bec6732cb81cf7e GIT binary patch literal 74752 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

    #p_Oq(Y?wy%_D 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

    dX0F_>g4*MO1wQ|>HMC+)-1Sfk$d{)F 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

      wS}nK~EP6%Rzt9Y6rMYyj|0aJgUd7qd6c# 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%0A?m>EG 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

      -3)LX+yb90CbE)#27ytV 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

      7;tMQ> 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%0DUVqH&v+nutAH==^=UUX+lXh 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 H`JDd)poy7v literal 0 HcmV?d00001