From 38336ec160d217a88c7c3106e3b93c95968bad37 Mon Sep 17 00:00:00 2001 From: "DANSPC\\Dan" Date: Sun, 1 Jun 2025 13:20:38 +0200 Subject: [PATCH 1/6] shoemaker integration --- .idea/.idea.PatchManager/.idea/.gitignore | 13 + .idea/.idea.PatchManager/.idea/.name | 1 + Directory.Build.props.meta | 7 + Editor.meta | 3 + Editor/PatchImporter.cs | 17 + Editor/PatchImporter.cs.meta | 3 + Editor/Tests.meta | 3 + Editor/Tests/ParsingTests.cs | 3093 +++++++++++++++++ Editor/Tests/ParsingTests.cs.meta | 11 + Editor/Tests/Validators.meta | 8 + Editor/Tests/Validators/ArgumentValidator.cs | 34 + .../Validators/ArgumentValidator.cs.meta | 11 + Editor/Tests/Validators/Attributes.meta | 8 + .../RunAtStageAttributeValidator.cs | 21 + .../RunAtStageAttributeValidator.cs.meta | 11 + Editor/Tests/Validators/BlockValidator.cs | 47 + .../Tests/Validators/BlockValidator.cs.meta | 11 + .../Tests/Validators/CallArgumentValidator.cs | 29 + .../Validators/CallArgumentValidator.cs.meta | 11 + Editor/Tests/Validators/Expressions.meta | 8 + .../Validators/Expressions/BinaryValidator.cs | 27 + .../Expressions/BinaryValidator.cs.meta | 11 + .../Validators/Expressions/ListValidator.cs | 48 + .../Expressions/ListValidator.cs.meta | 11 + .../Expressions/MemberCallValidator.cs | 37 + .../Expressions/MemberCallValidator.cs.meta | 11 + .../Validators/Expressions/ObjectValidator.cs | 48 + .../Expressions/ObjectValidator.cs.meta | 11 + .../Expressions/SimpleCallValidator.cs | 33 + .../Expressions/SimpleCallValidator.cs.meta | 11 + .../Expressions/TernaryValidator.cs | 32 + .../Expressions/TernaryValidator.cs.meta | 11 + .../Validators/Expressions/UnaryValidator.cs | 22 + .../Expressions/UnaryValidator.cs.meta | 11 + .../Validators/Expressions/ValueValidator.cs | 99 + .../Expressions/ValueValidator.cs.meta | 11 + .../Expressions/VariableReferenceValidator.cs | 24 + .../VariableReferenceValidator.cs.meta | 11 + Editor/Tests/Validators/FalseValidator.cs | 17 + .../Tests/Validators/FalseValidator.cs.meta | 11 + Editor/Tests/Validators/KeyValueValidator.cs | 25 + .../Validators/KeyValueValidator.cs.meta | 11 + Editor/Tests/Validators/ParseValidator.cs | 37 + .../Tests/Validators/ParseValidator.cs.meta | 11 + Editor/Tests/Validators/PatchValidator.cs | 50 + .../Tests/Validators/PatchValidator.cs.meta | 11 + Editor/Tests/Validators/Selectors.meta | 8 + .../Selectors/ChildSelectorValidator.cs | 24 + .../Selectors/ChildSelectorValidator.cs.meta | 11 + .../Selectors/ClassSelectorValidator.cs | 21 + .../Selectors/ClassSelectorValidator.cs.meta | 11 + .../Selectors/CombinationSelectorValidator.cs | 45 + .../CombinationSelectorValidator.cs.meta | 11 + .../Selectors/ElementSelectorValidator.cs | 21 + .../ElementSelectorValidator.cs.meta | 11 + .../IntersectionSelectorValidator.cs | 44 + .../IntersectionSelectorValidator.cs.meta | 11 + .../Selectors/NameSelectorValidator.cs | 21 + .../Selectors/NameSelectorValidator.cs.meta | 11 + .../Selectors/RulesetSelectorValidator.cs | 21 + .../RulesetSelectorValidator.cs.meta | 11 + .../Selectors/WildcardSelectorValidator.cs | 17 + .../WildcardSelectorValidator.cs.meta | 11 + .../WithoutClassSelectorValidator.cs | 21 + .../WithoutClassSelectorValidator.cs.meta | 11 + .../Selectors/WithoutNameSelectorValidator.cs | 21 + .../WithoutNameSelectorValidator.cs.meta | 11 + Editor/Tests/Validators/Statements.meta | 8 + .../Statements/ConditionalValidator.cs | 40 + .../Statements/ConditionalValidator.cs.meta | 11 + .../Validators/Statements/FunctionLevel.meta | 8 + .../FunctionLevel/ReturnValidator.cs | 24 + .../FunctionLevel/ReturnValidator.cs.meta | 11 + .../Statements/SelectionBlockValidator.cs | 38 + .../SelectionBlockValidator.cs.meta | 11 + .../Validators/Statements/SelectionLevel.meta | 8 + .../SelectionLevel/DeleteValueValidator.cs | 17 + .../DeleteValueValidator.cs.meta | 11 + .../SelectionLevel/FieldValidator.cs | 36 + .../SelectionLevel/FieldValidator.cs.meta | 11 + .../SelectionLevel/MergeValueValidator.cs | 21 + .../MergeValueValidator.cs.meta | 11 + .../SelectionLevel/MixinIncludeValidator.cs | 35 + .../MixinIncludeValidator.cs.meta | 11 + .../SelectionLevel/SetValueValidator.cs | 24 + .../SelectionLevel/SetValueValidator.cs.meta | 11 + .../Tests/Validators/Statements/TopLevel.meta | 8 + .../Statements/TopLevel/FunctionValidator.cs | 42 + .../TopLevel/FunctionValidator.cs.meta | 11 + .../Statements/TopLevel/ImportValidator.cs | 25 + .../TopLevel/ImportValidator.cs.meta | 11 + .../Statements/TopLevel/MixinValidator.cs | 41 + .../TopLevel/MixinValidator.cs.meta | 11 + .../VariableDeclarationValidator.cs | 30 + .../VariableDeclarationValidator.cs.meta | 11 + LICENSE.meta | 7 + Package.nuspec.meta | 7 + PatchManager.sln.DotSettings.meta | 7 + PatchManager.sln.meta | 7 + README.md.meta | 7 + Runtime.meta | 3 + Runtime/Core.meta | 3 + Runtime/Core/Assets.meta | 8 + Runtime/Core/Assets/ArchiveResourceLocator.cs | 62 + .../Assets/ArchiveResourceLocator.cs.meta | 11 + .../Core/Assets/ArchiveResourceProvider.cs | 41 + .../Assets/ArchiveResourceProvider.cs.meta | 11 + Runtime/Core/Assets/Locators.cs | 42 + Runtime/Core/Assets/Locators.cs.meta | 11 + Runtime/Core/Assets/PatchingManager.cs | 367 ++ Runtime/Core/Assets/PatchingManager.cs.meta | 11 + Runtime/Core/Cache.meta | 8 + Runtime/Core/Cache/Archive.cs | 114 + Runtime/Core/Cache/Archive.cs.meta | 11 + Runtime/Core/Cache/CacheManager.cs | 90 + Runtime/Core/Cache/CacheManager.cs.meta | 11 + Runtime/Core/Cache/Json.meta | 8 + Runtime/Core/Cache/Json/CacheEntry.cs | 30 + Runtime/Core/Cache/Json/CacheEntry.cs.meta | 11 + Runtime/Core/Cache/Json/Inventory.cs | 96 + Runtime/Core/Cache/Json/Inventory.cs.meta | 11 + Runtime/Core/Cache/Json/PatchHashes.cs | 45 + Runtime/Core/Cache/Json/PatchHashes.cs.meta | 11 + Runtime/Core/CoreModule.cs | 213 ++ Runtime/Core/CoreModule.cs.meta | 11 + Runtime/Core/Flow.meta | 8 + Runtime/Core/Flow/FlowAction.cs | 36 + Runtime/Core/Flow/FlowAction.cs.meta | 11 + Runtime/Core/Flow/FlowManager.cs | 52 + Runtime/Core/Flow/FlowManager.cs.meta | 11 + Runtime/Core/Utility.meta | 8 + Runtime/Core/Utility/Hash.cs | 55 + Runtime/Core/Utility/Hash.cs.meta | 11 + Runtime/Core/Utility/Versions.cs | 29 + Runtime/Core/Utility/Versions.cs.meta | 11 + Runtime/Generic.meta | 8 + Runtime/Generic/GenericModule.cs | 9 + Runtime/Generic/GenericModule.cs.meta | 3 + Runtime/Generic/SassyPatching.meta | 8 + Runtime/Generic/SassyPatching/Rulesets.meta | 8 + .../SassyPatching/Rulesets/JsonRuleset.cs | 37 + .../Rulesets/JsonRuleset.cs.meta | 11 + Runtime/Missions.meta | 3 + Runtime/Missions/Builtins.meta | 8 + Runtime/Missions/Builtins/MissionsBuiltins.cs | 31 + .../Builtins/MissionsBuiltins.cs.meta | 11 + Runtime/Missions/MissionsModule.cs | 9 + Runtime/Missions/MissionsModule.cs.meta | 3 + Runtime/Missions/MissionsTypes.cs | 58 + Runtime/Missions/MissionsTypes.cs.meta | 11 + Runtime/Missions/Modifiables.meta | 8 + .../Missions/Modifiables/MissionModifiable.cs | 40 + .../Modifiables/MissionModifiable.cs.meta | 11 + Runtime/Missions/Rulesets.meta | 8 + Runtime/Missions/Rulesets/MissionRuleset.cs | 37 + .../Missions/Rulesets/MissionRuleset.cs.meta | 11 + Runtime/Missions/Selectables.meta | 8 + .../Missions/Selectables/ActionsSelectable.cs | 132 + .../Selectables/ActionsSelectable.cs.meta | 11 + .../Selectables/ConditionSetSelectable.cs | 140 + .../ConditionSetSelectable.cs.meta | 11 + .../Selectables/ContentBranchSelectable.cs | 84 + .../ContentBranchSelectable.cs.meta | 11 + .../Selectables/ContentBranchesSelectable.cs | 102 + .../ContentBranchesSelectable.cs.meta | 11 + .../Selectables/MissionRewardSelectable.cs | 113 + .../MissionRewardSelectable.cs.meta | 11 + .../Missions/Selectables/MissionSelectable.cs | 112 + .../Selectables/MissionSelectable.cs.meta | 11 + .../Missions/Selectables/StageSelectable.cs | 155 + .../Selectables/StageSelectable.cs.meta | 11 + .../Missions/Selectables/StagesSelectable.cs | 103 + .../Selectables/StagesSelectable.cs.meta | 11 + Runtime/Parts.meta | 3 + Runtime/Parts/Attributes.meta | 8 + .../Attributes/ModuleDataAdapterAttribute.cs | 23 + .../ModuleDataAdapterAttribute.cs.meta | 11 + Runtime/Parts/Builtins.meta | 8 + Runtime/Parts/Builtins/PartsBuiltins.cs | 327 ++ Runtime/Parts/Builtins/PartsBuiltins.cs.meta | 11 + Runtime/Parts/Modifiables.meta | 8 + Runtime/Parts/Modifiables/PartModifiable.cs | 51 + .../Parts/Modifiables/PartModifiable.cs.meta | 11 + Runtime/Parts/PartsModule.cs | 23 + Runtime/Parts/PartsModule.cs.meta | 11 + Runtime/Parts/PartsUtilities.cs | 127 + Runtime/Parts/PartsUtilities.cs.meta | 11 + Runtime/Parts/Patchers.meta | 8 + Runtime/Parts/Patchers/OABUtilsPatcher.cs | 13 + .../Parts/Patchers/OABUtilsPatcher.cs.meta | 11 + .../Parts/Patchers/PartModuleLoadPatcher.cs | 80 + .../Patchers/PartModuleLoadPatcher.cs.meta | 11 + .../UpdateSavedVesselPartDefinitions.cs | 88 + .../UpdateSavedVesselPartDefinitions.cs.meta | 11 + Runtime/Parts/Rulesets.meta | 8 + Runtime/Parts/Rulesets/PartsRuleset.cs | 111 + Runtime/Parts/Rulesets/PartsRuleset.cs.meta | 11 + Runtime/Parts/Selectables.meta | 8 + .../Parts/Selectables/DataEngineSelectable.cs | 136 + .../Selectables/DataEngineSelectable.cs.meta | 11 + Runtime/Parts/Selectables/ModuleSelectable.cs | 138 + .../Selectables/ModuleSelectable.cs.meta | 11 + Runtime/Parts/Selectables/PartSelectable.cs | 159 + .../Parts/Selectables/PartSelectable.cs.meta | 11 + .../ResourceContainerSelectable.cs | 17 + .../ResourceContainerSelectable.cs.meta | 11 + .../ResourceContainersSelectable.cs | 92 + .../ResourceContainersSelectable.cs.meta | 11 + Runtime/PatchManager.Resources.meta | 8 + .../NonStageableResourcesUIController.cs | 113 + .../NonStageableResourcesUIController.cs.meta | 3 + .../PatchManager.Resources/ResourcesModule.cs | 58 + .../ResourcesModule.cs.meta | 11 + Runtime/PatchManager.Resources/Rulesets.meta | 8 + .../Rulesets/ResourceRuleset.cs | 55 + .../Rulesets/ResourceRuleset.cs.meta | 11 + .../Rulesets/ResourceUnitRuleset.cs | 32 + .../Rulesets/ResourceUnitRuleset.cs.meta | 3 + .../PatchManager.Resources/Selectables.meta | 8 + .../Selectables/RecipeSelectable.cs | 118 + .../Selectables/RecipeSelectable.cs.meta | 11 + .../Selectables/ResourceSelectable.cs | 89 + .../Selectables/ResourceSelectable.cs.meta | 11 + Runtime/PatchManager.cs | 98 + Runtime/PatchManager.cs.meta | 3 + Runtime/Planets.meta | 8 + Runtime/Planets/Shoemaker.meta | 8 + .../Shoemaker}/Directory.Build.targets | 56 +- .../Shoemaker/Directory.Build.targets.meta | 7 + Runtime/Planets/Shoemaker/Modifiables.meta | 8 + .../AtmosphereOverrideModifiable.cs | 28 + .../AtmosphereOverrideModifiable.cs.meta | 11 + .../Modifiables/CelestialBodyModifiable.cs | 28 + .../CelestialBodyModifiable.cs.meta | 11 + .../Shoemaker/Modifiables/GalaxyModifiable.cs | 28 + .../Modifiables/GalaxyModifiable.cs.meta | 11 + .../VolumeCloudOverrideModifiable.cs | 28 + .../VolumeCloudOverrideModifiable.cs.meta | 11 + Runtime/Planets/Shoemaker/OverrideManager.cs | 17 + .../Planets/Shoemaker/OverrideManager.cs.meta | 11 + Runtime/Planets/Shoemaker/Overrides.meta | 8 + .../Shoemaker/Overrides/AtmosphereOverride.cs | 87 + .../Overrides/AtmosphereOverride.cs.meta | 11 + .../Shoemaker/Overrides/CloudsDataOverride.cs | 48 + .../Overrides/CloudsDataOverride.cs.meta | 11 + .../Planets/Shoemaker/Overrides/IOverride.cs | 7 + .../Shoemaker/Overrides/IOverride.cs.meta | 11 + .../VolumeCloudConfigurationOverride.cs | 158 + .../VolumeCloudConfigurationOverride.cs.meta | 11 + Runtime/Planets/Shoemaker/Patches.meta | 8 + .../AtmosphereScatterManagerPatches.cs | 35 + .../AtmosphereScatterManagerPatches.cs.meta | 11 + .../Patches/CelestialBodyBehaviorPatches.cs | 61 + .../CelestialBodyBehaviorPatches.cs.meta | 11 + .../Patches/CloudRenderHelperPatches.cs | 35 + .../Patches/CloudRenderHelperPatches.cs.meta | 11 + .../ScaledCloudDataModelComponentPatches.cs | 20 + ...aledCloudDataModelComponentPatches.cs.meta | 11 + Runtime/Planets/Shoemaker/PlanetsModule.cs | 38 + .../Planets/Shoemaker/PlanetsModule.cs.meta | 11 + Runtime/Planets/Shoemaker/Rulesets.meta | 8 + .../Rulesets/AtmosphereOverrideRuleset.cs | 31 + .../AtmosphereOverrideRuleset.cs.meta | 11 + .../Rulesets/CelestialBodyRuleset.cs | 35 + .../Rulesets/CelestialBodyRuleset.cs.meta | 11 + .../Shoemaker/Rulesets/GalaxyRuleset.cs | 42 + .../Shoemaker/Rulesets/GalaxyRuleset.cs.meta | 11 + .../Rulesets/VolumeCloudOverrideRuleset.cs | 30 + .../VolumeCloudOverrideRuleset.cs.meta | 11 + Runtime/Planets/Shoemaker/Selectables.meta | 8 + .../AtmosphereOverrideSelectable.cs | 78 + .../AtmosphereOverrideSelectable.cs.meta | 11 + .../Selectables/CelestialBodySelectable.cs | 87 + .../CelestialBodySelectable.cs.meta | 11 + .../Shoemaker/Selectables/GalaxySelectable.cs | 122 + .../Selectables/GalaxySelectable.cs.meta | 11 + .../Selectables/VolumeCloudSelectable.cs | 108 + .../Selectables/VolumeCloudSelectable.cs.meta | 11 + Runtime/Planets/Shoemaker/Shoemaker.csproj | 21 + .../Planets/Shoemaker/Shoemaker.csproj.meta | 7 + Runtime/Planets/Shoemaker/Utility.meta | 8 + .../Planets/Shoemaker/Utility/Extensions.cs | 10 + .../Shoemaker/Utility/Extensions.cs.meta | 11 + .../Planets/Shoemaker/Utility/GlobalUsings.cs | 3 + .../Shoemaker/Utility/GlobalUsings.cs.meta | 11 + Runtime/Planets/Shoemaker/swinfo.json | 30 + Runtime/Planets/Shoemaker/swinfo.json.meta | 7 + Runtime/SassyPatching.meta | 3 + Runtime/SassyPatching/Attributes.meta | 8 + .../Attributes/PatcherRulesetAttribute.cs | 37 + .../PatcherRulesetAttribute.cs.meta | 11 + .../Attributes/SassyConstantAttribute.cs | 13 + .../Attributes/SassyConstantAttribute.cs.meta | 11 + .../Attributes/SassyLibraryAttribute.cs | 33 + .../Attributes/SassyLibraryAttribute.cs.meta | 11 + .../Attributes/SassyMethodAttribute.cs | 28 + .../Attributes/SassyMethodAttribute.cs.meta | 11 + .../Attributes/SassyNameAttribute.cs | 14 + .../Attributes/SassyNameAttribute.cs.meta | 11 + .../Attributes/VarArgsAttribute.cs | 13 + .../Attributes/VarArgsAttribute.cs.meta | 11 + Runtime/SassyPatching/BaseSelectable.cs | 73 + Runtime/SassyPatching/BaseSelectable.cs.meta | 11 + Runtime/SassyPatching/Builtins.meta | 8 + .../SassyPatching/Builtins/ConfigBuiltins.cs | 20 + .../Builtins/ConfigBuiltins.cs.meta | 11 + .../SassyPatching/Builtins/DebugBuiltins.cs | 35 + .../Builtins/DebugBuiltins.cs.meta | 11 + .../Builtins/DictionaryBuiltins.cs | 58 + .../Builtins/DictionaryBuiltins.cs.meta | 11 + .../Builtins/FunctionalBuiltins.cs | 80 + .../Builtins/FunctionalBuiltins.cs.meta | 11 + .../SassyPatching/Builtins/ListBuiltins.cs | 236 ++ .../Builtins/ListBuiltins.cs.meta | 11 + .../SassyPatching/Builtins/MathBuiltins.cs | 125 + .../Builtins/MathBuiltins.cs.meta | 11 + .../SassyPatching/Builtins/MetaBuiltins.cs | 20 + .../Builtins/MetaBuiltins.cs.meta | 11 + .../Builtins/ReflectionBuiltins.cs | 24 + .../Builtins/ReflectionBuiltins.cs.meta | 11 + .../SassyPatching/Builtins/StringBuiltins.cs | 44 + .../Builtins/StringBuiltins.cs.meta | 11 + .../SassyPatching/Builtins/TypeConversion.cs | 90 + .../Builtins/TypeConversion.cs.meta | 11 + Runtime/SassyPatching/Coordinate.cs | 31 + Runtime/SassyPatching/Coordinate.cs.meta | 11 + Runtime/SassyPatching/DataValue.cs | 1317 +++++++ Runtime/SassyPatching/DataValue.cs.meta | 11 + Runtime/SassyPatching/Exceptions.meta | 8 + .../BinaryExpressionTypeException.cs | 12 + .../BinaryExpressionTypeException.cs.meta | 11 + .../Exceptions/DataValueOperationException.cs | 11 + .../DataValueOperationException.cs.meta | 11 + .../DictionaryKeyNotFoundException.cs | 12 + .../DictionaryKeyNotFoundException.cs.meta | 11 + .../Exceptions/FunctionReturnException.cs | 14 + .../FunctionReturnException.cs.meta | 11 + .../Exceptions/ImportException.cs | 9 + .../Exceptions/ImportException.cs.meta | 11 + .../Exceptions/IncorrectTypeException.cs | 14 + .../Exceptions/IncorrectTypeException.cs.meta | 11 + .../Exceptions/InterpolationException.cs | 7 + .../Exceptions/InterpolationException.cs.meta | 11 + .../Exceptions/InterpreterException.cs | 20 + .../Exceptions/InterpreterException.cs.meta | 11 + .../InvalidVariableReferenceException.cs | 12 + .../InvalidVariableReferenceException.cs.meta | 11 + .../Exceptions/InvocationException.cs | 14 + .../Exceptions/InvocationException.cs.meta | 11 + .../ListIndexOutOfRangeException.cs | 9 + .../ListIndexOutOfRangeException.cs.meta | 11 + .../Exceptions/NotModifiableException.cs | 15 + .../Exceptions/NotModifiableException.cs.meta | 11 + .../Exceptions/TypeConversionException.cs | 14 + .../TypeConversionException.cs.meta | 11 + .../Exceptions/UnaryTypeException.cs | 12 + .../Exceptions/UnaryTypeException.cs.meta | 11 + Runtime/SassyPatching/Execution.meta | 8 + .../Execution/BoundPatchFunction.cs | 30 + .../Execution/BoundPatchFunction.cs.meta | 11 + .../SassyPatching/Execution/Environment.cs | 97 + .../Execution/Environment.cs.meta | 11 + .../Execution/GlobalEnvironment.cs | 74 + .../Execution/GlobalEnvironment.cs.meta | 11 + .../Execution/ManagedPatchFunction.cs | 156 + .../Execution/ManagedPatchFunction.cs.meta | 11 + .../Execution/ManagedPatchLibrary.cs | 45 + .../Execution/ManagedPatchLibrary.cs.meta | 11 + .../SassyPatching/Execution/PatchArgument.cs | 20 + .../Execution/PatchArgument.cs.meta | 11 + .../SassyPatching/Execution/PatchFunction.cs | 18 + .../Execution/PatchFunction.cs.meta | 11 + .../SassyPatching/Execution/PatchLibrary.cs | 14 + .../Execution/PatchLibrary.cs.meta | 11 + Runtime/SassyPatching/Execution/PatchMixin.cs | 89 + .../Execution/PatchMixin.cs.meta | 11 + .../SassyPatching/Execution/SassyGenerator.cs | 54 + .../Execution/SassyGenerator.cs.meta | 11 + .../Execution/SassyPatchClosure.cs | 83 + .../Execution/SassyPatchClosure.cs.meta | 11 + .../Execution/SassyPatchFunction.cs | 83 + .../Execution/SassyPatchFunction.cs.meta | 11 + .../Execution/SassyPatchLibrary.cs | 19 + .../Execution/SassyPatchLibrary.cs.meta | 11 + .../Execution/SassyTextPatcher.cs | 65 + .../Execution/SassyTextPatcher.cs.meta | 11 + .../Execution/SelectableWithEnvironment.cs | 20 + .../SelectableWithEnvironment.cs.meta | 11 + Runtime/SassyPatching/Execution/Stage.cs | 18 + Runtime/SassyPatching/Execution/Stage.cs.meta | 11 + Runtime/SassyPatching/Execution/Universe.cs | 552 +++ .../SassyPatching/Execution/Universe.cs.meta | 11 + Runtime/SassyPatching/Interfaces.meta | 8 + .../SassyPatching/Interfaces/IModifiable.cs | 38 + .../Interfaces/IModifiable.cs.meta | 11 + Runtime/SassyPatching/Interfaces/INewAsset.cs | 14 + .../Interfaces/INewAsset.cs.meta | 11 + .../Interfaces/IPatcherRuleSet.cs | 35 + .../Interfaces/IPatcherRuleSet.cs.meta | 11 + .../SassyPatching/Interfaces/ISelectable.cs | 73 + .../Interfaces/ISelectable.cs.meta | 11 + Runtime/SassyPatching/Modifiables.meta | 8 + .../Modifiables/CustomJTokenModifiable.cs | 109 + .../CustomJTokenModifiable.cs.meta | 11 + .../Modifiables/JTokenModifiable.cs | 88 + .../Modifiables/JTokenModifiable.cs.meta | 11 + Runtime/SassyPatching/NewAssets.meta | 8 + .../NewAssets/NewGenericAsset.cs | 35 + .../NewAssets/NewGenericAsset.cs.meta | 11 + Runtime/SassyPatching/Nodes.meta | 8 + Runtime/SassyPatching/Nodes/Argument.cs | 32 + Runtime/SassyPatching/Nodes/Argument.cs.meta | 11 + Runtime/SassyPatching/Nodes/Attributes.meta | 8 + .../Nodes/Attributes/NewAttribute.cs | 11 + .../Nodes/Attributes/NewAttribute.cs.meta | 11 + .../Nodes/Attributes/RequireExpressions.meta | 8 + .../RequireExpressions/RequireAnd.cs | 20 + .../RequireExpressions/RequireAnd.cs.meta | 11 + .../RequireExpressions/RequireExpression.cs | 18 + .../RequireExpression.cs.meta | 11 + .../RequireExpressions/RequireGuid.cs | 16 + .../RequireExpressions/RequireGuid.cs.meta | 11 + .../RequireExpressions/RequireNot.cs | 13 + .../RequireExpressions/RequireNot.cs.meta | 11 + .../RequireExpressions/RequireOr.cs | 20 + .../RequireExpressions/RequireOr.cs.meta | 11 + .../Nodes/Attributes/RequireModAttribute.cs | 14 + .../Attributes/RequireModAttribute.cs.meta | 11 + .../Nodes/Attributes/RunAtStageAttribute.cs | 18 + .../Attributes/RunAtStageAttribute.cs.meta | 11 + .../Nodes/Attributes/SelectorAttribute.cs | 19 + .../Attributes/SelectorAttribute.cs.meta | 11 + Runtime/SassyPatching/Nodes/Block.cs | 48 + Runtime/SassyPatching/Nodes/Block.cs.meta | 11 + Runtime/SassyPatching/Nodes/CallArgument.cs | 54 + .../SassyPatching/Nodes/CallArgument.cs.meta | 11 + Runtime/SassyPatching/Nodes/ErrorNode.cs | 26 + Runtime/SassyPatching/Nodes/ErrorNode.cs.meta | 11 + Runtime/SassyPatching/Nodes/Expressions.meta | 8 + .../Nodes/Expressions/Binary.meta | 8 + .../Nodes/Expressions/Binary/Add.cs | 30 + .../Nodes/Expressions/Binary/Add.cs.meta | 11 + .../Nodes/Expressions/Binary/And.cs | 19 + .../Nodes/Expressions/Binary/And.cs.meta | 11 + .../Nodes/Expressions/Binary/Binary.cs | 44 + .../Nodes/Expressions/Binary/Binary.cs.meta | 11 + .../Nodes/Expressions/Binary/Divide.cs | 30 + .../Nodes/Expressions/Binary/Divide.cs.meta | 11 + .../Nodes/Expressions/Binary/EqualTo.cs | 19 + .../Nodes/Expressions/Binary/EqualTo.cs.meta | 11 + .../Nodes/Expressions/Binary/GreaterThan.cs | 31 + .../Expressions/Binary/GreaterThan.cs.meta | 11 + .../Expressions/Binary/GreaterThanEqual.cs | 31 + .../Binary/GreaterThanEqual.cs.meta | 11 + .../Nodes/Expressions/Binary/LesserThan.cs | 32 + .../Expressions/Binary/LesserThan.cs.meta | 11 + .../Expressions/Binary/LesserThanEqual.cs | 30 + .../Binary/LesserThanEqual.cs.meta | 11 + .../Nodes/Expressions/Binary/Multiply.cs | 34 + .../Nodes/Expressions/Binary/Multiply.cs.meta | 11 + .../Nodes/Expressions/Binary/NotEqualTo.cs | 19 + .../Expressions/Binary/NotEqualTo.cs.meta | 11 + .../Nodes/Expressions/Binary/Or.cs | 20 + .../Nodes/Expressions/Binary/Or.cs.meta | 11 + .../Nodes/Expressions/Binary/Remainder.cs | 31 + .../Expressions/Binary/Remainder.cs.meta | 11 + .../Nodes/Expressions/Binary/Subscript.cs | 42 + .../Expressions/Binary/Subscript.cs.meta | 11 + .../Nodes/Expressions/Binary/Subtract.cs | 31 + .../Nodes/Expressions/Binary/Subtract.cs.meta | 11 + .../Nodes/Expressions/Closure.cs | 32 + .../Nodes/Expressions/Closure.cs.meta | 11 + .../Nodes/Expressions/Expression.cs | 28 + .../Nodes/Expressions/Expression.cs.meta | 11 + .../Nodes/Expressions/ListNode.cs | 27 + .../Nodes/Expressions/ListNode.cs.meta | 11 + .../Expressions/LocalVariableReference.cs | 26 + .../LocalVariableReference.cs.meta | 11 + .../Nodes/Expressions/MemberCall.cs | 83 + .../Nodes/Expressions/MemberCall.cs.meta | 11 + .../Nodes/Expressions/ObjectNode.cs | 27 + .../Nodes/Expressions/ObjectNode.cs.meta | 11 + .../Nodes/Expressions/SimpleCall.cs | 51 + .../Nodes/Expressions/SimpleCall.cs.meta | 11 + .../Nodes/Expressions/Ternary.cs | 35 + .../Nodes/Expressions/Ternary.cs.meta | 11 + .../Nodes/Expressions/Unary.meta | 8 + .../Nodes/Expressions/Unary/Implicit.cs | 29 + .../Nodes/Expressions/Unary/Implicit.cs.meta | 11 + .../Nodes/Expressions/Unary/ImplicitAdd.cs | 29 + .../Expressions/Unary/ImplicitAdd.cs.meta | 11 + .../Nodes/Expressions/Unary/ImplicitDivide.cs | 27 + .../Expressions/Unary/ImplicitDivide.cs.meta | 11 + .../Expressions/Unary/ImplicitMultiply.cs | 28 + .../Unary/ImplicitMultiply.cs.meta | 11 + .../Expressions/Unary/ImplicitSubtract.cs | 27 + .../Unary/ImplicitSubtract.cs.meta | 11 + .../Nodes/Expressions/Unary/Negate.cs | 26 + .../Nodes/Expressions/Unary/Negate.cs.meta | 11 + .../Nodes/Expressions/Unary/Not.cs | 15 + .../Nodes/Expressions/Unary/Not.cs.meta | 11 + .../Nodes/Expressions/Unary/Positive.cs | 14 + .../Nodes/Expressions/Unary/Positive.cs.meta | 11 + .../Nodes/Expressions/Unary/Unary.cs | 30 + .../Nodes/Expressions/Unary/Unary.cs.meta | 11 + .../Nodes/Expressions/ValueNode.cs | 40 + .../Nodes/Expressions/ValueNode.cs.meta | 11 + .../Nodes/Expressions/VariableReference.cs | 35 + .../Expressions/VariableReference.cs.meta | 11 + Runtime/SassyPatching/Nodes/Indexers.meta | 8 + .../Nodes/Indexers/EverythingIndexer.cs | 7 + .../Nodes/Indexers/EverythingIndexer.cs.meta | 11 + .../SassyPatching/Nodes/Indexers/Indexer.cs | 19 + .../Nodes/Indexers/Indexer.cs.meta | 11 + .../Nodes/Indexers/SingleIndexer.cs | 13 + .../Nodes/Indexers/SingleIndexer.cs.meta | 11 + Runtime/SassyPatching/Nodes/KeyValueNode.cs | 31 + .../SassyPatching/Nodes/KeyValueNode.cs.meta | 11 + Runtime/SassyPatching/Nodes/Node.cs | 30 + Runtime/SassyPatching/Nodes/Node.cs.meta | 11 + Runtime/SassyPatching/Nodes/SassyPatch.cs | 30 + .../SassyPatching/Nodes/SassyPatch.cs.meta | 11 + Runtime/SassyPatching/Nodes/Selectors.meta | 8 + .../Nodes/Selectors/ChildSelector.cs | 57 + .../Nodes/Selectors/ChildSelector.cs.meta | 11 + .../Nodes/Selectors/ClassCaptureSelector.cs | 64 + .../Selectors/ClassCaptureSelector.cs.meta | 11 + .../Nodes/Selectors/ClassSelector.cs | 43 + .../Nodes/Selectors/ClassSelector.cs.meta | 11 + .../Nodes/Selectors/CombinationSelector.cs | 84 + .../Selectors/CombinationSelector.cs.meta | 11 + .../Selectors/ElementAdditionSelector.cs | 72 + .../Selectors/ElementAdditionSelector.cs.meta | 11 + .../Nodes/Selectors/ElementSelector.cs | 59 + .../Nodes/Selectors/ElementSelector.cs.meta | 11 + .../Nodes/Selectors/EnsureSelector.cs | 89 + .../Nodes/Selectors/EnsureSelector.cs.meta | 11 + .../Nodes/Selectors/IntersectionSelector.cs | 72 + .../Selectors/IntersectionSelector.cs.meta | 11 + .../Nodes/Selectors/NameSelector.cs | 43 + .../Nodes/Selectors/NameSelector.cs.meta | 11 + .../Nodes/Selectors/RulesetSelector.cs | 79 + .../Nodes/Selectors/RulesetSelector.cs.meta | 11 + .../SassyPatching/Nodes/Selectors/Selector.cs | 50 + .../Nodes/Selectors/Selector.cs.meta | 11 + .../Nodes/Selectors/WildcardSelector.cs | 36 + .../Nodes/Selectors/WildcardSelector.cs.meta | 11 + .../Nodes/Selectors/WithoutClassSelector.cs | 43 + .../Selectors/WithoutClassSelector.cs.meta | 11 + .../Nodes/Selectors/WithoutNameSelector.cs | 43 + .../Selectors/WithoutNameSelector.cs.meta | 11 + Runtime/SassyPatching/Nodes/Statements.meta | 8 + .../Nodes/Statements/Conditional.cs | 81 + .../Nodes/Statements/Conditional.cs.meta | 11 + .../SassyPatching/Nodes/Statements/Each.cs | 224 ++ .../Nodes/Statements/Each.cs.meta | 11 + Runtime/SassyPatching/Nodes/Statements/For.cs | 349 ++ .../Nodes/Statements/For.cs.meta | 11 + .../Nodes/Statements/FunctionLevel.meta | 8 + .../Nodes/Statements/FunctionLevel/Return.cs | 27 + .../Statements/FunctionLevel/Return.cs.meta | 11 + .../Nodes/Statements/SelectionBlock.cs | 204 ++ .../Nodes/Statements/SelectionBlock.cs.meta | 11 + .../Nodes/Statements/SelectionLevel.meta | 8 + .../Statements/SelectionLevel/DeleteValue.cs | 31 + .../SelectionLevel/DeleteValue.cs.meta | 11 + .../Nodes/Statements/SelectionLevel/Field.cs | 163 + .../Statements/SelectionLevel/Field.cs.meta | 11 + .../SelectionLevel/ISelectionAction.cs | 20 + .../SelectionLevel/ISelectionAction.cs.meta | 11 + .../Statements/SelectionLevel/MergeValue.cs | 57 + .../SelectionLevel/MergeValue.cs.meta | 11 + .../SelectionLevel/MixinBlockInclude.cs | 64 + .../SelectionLevel/MixinBlockInclude.cs.meta | 11 + .../Statements/SelectionLevel/MixinInclude.cs | 54 + .../SelectionLevel/MixinInclude.cs.meta | 11 + .../Statements/SelectionLevel/MixinSlot.cs | 38 + .../SelectionLevel/MixinSlot.cs.meta | 11 + .../Statements/SelectionLevel/SetValue.cs | 46 + .../SelectionLevel/SetValue.cs.meta | 11 + .../Nodes/Statements/TopLevel.meta | 8 + .../Statements/TopLevel/ConfigCreation.cs | 41 + .../TopLevel/ConfigCreation.cs.meta | 11 + .../Nodes/Statements/TopLevel/ConfigUpdate.cs | 32 + .../Statements/TopLevel/ConfigUpdate.cs.meta | 11 + .../Nodes/Statements/TopLevel/Function.cs | 40 + .../Statements/TopLevel/Function.cs.meta | 11 + .../Nodes/Statements/TopLevel/Import.cs | 51 + .../Nodes/Statements/TopLevel/Import.cs.meta | 11 + .../Nodes/Statements/TopLevel/Mixin.cs | 37 + .../Nodes/Statements/TopLevel/Mixin.cs.meta | 11 + .../Statements/TopLevel/PatchDeclaration.cs | 26 + .../TopLevel/PatchDeclaration.cs.meta | 11 + .../Statements/TopLevel/StageDefinition.cs | 112 + .../TopLevel/StageDefinition.cs.meta | 11 + .../TopLevel/StageDefinitionAttribute.cs | 18 + .../TopLevel/StageDefinitionAttribute.cs.meta | 11 + .../Nodes/Statements/VariableDeclaration.cs | 167 + .../Statements/VariableDeclaration.cs.meta | 11 + .../SassyPatching/Nodes/Statements/While.cs | 58 + .../Nodes/Statements/While.cs.meta | 11 + Runtime/SassyPatching/SassyPatchGrammar.meta | 8 + .../SassyPatching/SassyPatchGrammar/gen.meta | 8 + .../SassyPatchGrammar/gen/sassy_lexer.interp | 0 .../gen/sassy_lexer.interp.meta | 7 + .../SassyPatchGrammar/gen/sassy_lexer.java | 0 .../gen/sassy_lexer.java.meta | 32 + .../SassyPatchGrammar/gen/sassy_lexer.tokens | 0 .../gen/sassy_lexer.tokens.meta | 7 + .../SassyPatchGrammar/sassy_lexer.cs | 0 .../SassyPatchGrammar/sassy_lexer.cs.meta | 11 + .../SassyPatchGrammar/sassy_lexer.g4 | 0 .../SassyPatchGrammar/sassy_lexer.g4.meta | 7 + .../SassyPatchGrammar/sassy_lexer.interp | 0 .../SassyPatchGrammar/sassy_lexer.interp.meta | 7 + .../SassyPatchGrammar/sassy_lexer.tokens | 0 .../SassyPatchGrammar/sassy_lexer.tokens.meta | 7 + .../SassyPatchGrammar/sassy_parser.cs | 0 .../SassyPatchGrammar/sassy_parser.cs.meta | 11 + .../SassyPatchGrammar/sassy_parser.g4 | 0 .../SassyPatchGrammar/sassy_parser.g4.meta | 7 + .../SassyPatchGrammar/sassy_parser.interp | 0 .../sassy_parser.interp.meta | 7 + .../SassyPatchGrammar/sassy_parser.tokens | 0 .../sassy_parser.tokens.meta | 7 + .../sassy_parserBaseListener.cs | 0 .../sassy_parserBaseListener.cs.meta | 11 + .../sassy_parserBaseVisitor.cs | 0 .../sassy_parserBaseVisitor.cs.meta | 11 + .../SassyPatchGrammar/sassy_parserListener.cs | 0 .../sassy_parserListener.cs.meta | 11 + .../SassyPatchGrammar/sassy_parserVisitor.cs | 0 .../sassy_parserVisitor.cs.meta | 11 + Runtime/SassyPatching/Selectables.meta | 8 + .../Selectables/JTokenSelectable.cs | 133 + .../Selectables/JTokenSelectable.cs.meta | 11 + Runtime/SassyPatching/SelectionUtilities.cs | 22 + .../SassyPatching/SelectionUtilities.cs.meta | 11 + Runtime/SassyPatching/Transformer.cs | 824 +++++ Runtime/SassyPatching/Transformer.cs.meta | 11 + Runtime/SassyPatching/Utility.meta | 8 + Runtime/SassyPatching/Utility/Extensions.cs | 131 + .../SassyPatching/Utility/Extensions.cs.meta | 11 + Runtime/Science.meta | 3 + Runtime/Science/Modifiables.meta | 8 + .../Modifiables/DiscoverablesModifiable.cs | 34 + .../DiscoverablesModifiable.cs.meta | 11 + .../Modifiables/ExperimentModifiable.cs | 37 + .../Modifiables/ExperimentModifiable.cs.meta | 11 + .../Science/Modifiables/RegionsModifiable.cs | 34 + .../Modifiables/RegionsModifiable.cs.meta | 11 + .../Science/Modifiables/ScienceModifiable.cs | 34 + .../Modifiables/ScienceModifiable.cs.meta | 11 + Runtime/Science/Rulesets.meta | 8 + .../Science/Rulesets/DiscoverablesRuleset.cs | 41 + .../Rulesets/DiscoverablesRuleset.cs.meta | 11 + Runtime/Science/Rulesets/ExperimentRuleset.cs | 40 + .../Rulesets/ExperimentRuleset.cs.meta | 11 + Runtime/Science/Rulesets/RegionsRuleset.cs | 42 + .../Science/Rulesets/RegionsRuleset.cs.meta | 11 + Runtime/Science/Rulesets/ScienceRuleset.cs | 31 + .../Science/Rulesets/ScienceRuleset.cs.meta | 11 + Runtime/Science/ScienceModule.cs | 13 + Runtime/Science/ScienceModule.cs.meta | 11 + Runtime/Science/Selectables.meta | 8 + .../Selectables/DiscoverablesSelectable.cs | 127 + .../DiscoverablesSelectable.cs.meta | 11 + .../Selectables/ExperimentSelectable.cs | 113 + .../Selectables/ExperimentSelectable.cs.meta | 11 + .../Science/Selectables/RegionsSelectable.cs | 127 + .../Selectables/RegionsSelectable.cs.meta | 11 + .../Science/Selectables/ScienceSelectable.cs | 107 + .../Selectables/ScienceSelectable.cs.meta | 11 + Runtime/Shared.meta | 3 + Runtime/Shared/Extensions.cs | 132 + Runtime/Shared/Extensions.cs.meta | 11 + Runtime/Shared/Interfaces.meta | 8 + .../Shared/Interfaces/ITextAssetGenerator.cs | 21 + .../Interfaces/ITextAssetGenerator.cs.meta | 11 + Runtime/Shared/Interfaces/ITextPatcher.cs | 22 + .../Shared/Interfaces/ITextPatcher.cs.meta | 11 + Runtime/Shared/Logging.cs | 87 + Runtime/Shared/Logging.cs.meta | 11 + Runtime/Shared/Modules.meta | 8 + Runtime/Shared/Modules/BaseModule.cs | 36 + Runtime/Shared/Modules/BaseModule.cs.meta | 11 + Runtime/Shared/Modules/IModule.cs | 43 + Runtime/Shared/Modules/IModule.cs.meta | 11 + Runtime/Shared/Modules/ModuleManager.cs | 60 + Runtime/Shared/Modules/ModuleManager.cs.meta | 11 + StandalonePatchTester/Program.cs | 86 - .../StandalonePatchTester.csproj | 20 - images.meta | 8 + patch_tests.meta | 8 + patch_tests/json.meta | 8 + patch_tests/patches.meta | 8 + plugin_template.meta | 8 + scripts.meta | 8 + .../Assets/ArchiveResourceLocator.cs | 58 - .../Assets/ArchiveResourceProvider.cs | 38 - src/PatchManager.Core/Assets/Locators.cs | 40 - .../Assets/PatchingManager.cs | 356 -- src/PatchManager.Core/Cache/Archive.cs | 111 - src/PatchManager.Core/Cache/CacheManager.cs | 83 - .../Cache/Json/CacheEntry.cs | 28 - src/PatchManager.Core/Cache/Json/Inventory.cs | 91 - .../Cache/Json/PatchHashes.cs | 43 - src/PatchManager.Core/CoreModule.cs | 222 -- src/PatchManager.Core/Flow/FlowAction.cs | 29 - src/PatchManager.Core/Flow/FlowManager.cs | 49 - src/PatchManager.Core/Flow/IAction.cs | 19 - .../PatchManager.Core.csproj | 14 - .../PatchManager.Core.csproj.DotSettings | 2 - .../Patches/Preload/AssetProviderPatch.cs | 52 - .../Patches/Runtime/ExternalAssetsPatch.cs | 63 - .../Patches/Runtime/GameManagerPatch.cs | 20 - .../Patches/Runtime/LoadingBarPatch.cs | 25 - src/PatchManager.Core/Utility/Hash.cs | 52 - src/PatchManager.Core/Utility/Versions.cs | 28 - src/PatchManager.Generic/GenericModule.cs | 10 - .../PatchManager.Generic.csproj | 8 - .../SassyPatching/Rulesets/JsonRuleset.cs | 35 - .../Builtins/MissionsBuiltins.cs | 30 - src/PatchManager.Missions/MissionsModule.cs | 12 - src/PatchManager.Missions/MissionsTypes.cs | 54 - .../Modifiables/MissionModifiable.cs | 39 - .../PatchManager.Missions.csproj | 11 - .../Rulesets/MissionRuleset.cs | 35 - .../Selectables/ActionsSelectable.cs | 129 - .../Selectables/ConditionSetSelectable.cs | 137 - .../Selectables/ContentBranchSelectable.cs | 82 - .../Selectables/ContentBranchesSelectable.cs | 100 - .../Selectables/MissionRewardSelectable.cs | 111 - .../Selectables/MissionSelectable.cs | 109 - .../Selectables/StageSelectable.cs | 152 - .../Selectables/StagesSelectable.cs | 101 - .../Attributes/ModuleDataAdapterAttribute.cs | 20 - .../Builtins/PartsBuiltins.cs | 323 -- .../Modifiables/PartModifiable.cs | 50 - src/PatchManager.Parts/PartsModule.cs | 22 - src/PatchManager.Parts/PartsUtilities.cs | 123 - .../PatchManager.Parts.csproj | 13 - .../Patchers/OABUtilsPatcher.cs | 33 - .../Patchers/PartDataDeserializePatcher.cs | 27 - .../Patchers/PartModuleLoadPatcher.cs | 183 - .../UpdateSavedVesselPartDefinitions.cs | 82 - .../Rulesets/PartsRuleset.cs | 109 - .../Selectables/DataEngineSelectable.cs | 134 - .../Selectables/ModuleSelectable.cs | 135 - .../Selectables/PartSelectable.cs | 155 - .../ResourceContainerSelectable.cs | 16 - .../ResourceContainersSelectable.cs | 90 - .../PatchManager.Resources.csproj | 8 - src/PatchManager.Resources/ResourcesModule.cs | 12 - .../Rulesets/ResourceRuleset.cs | 53 - .../Selectables/RecipeSelectable.cs | 116 - .../Selectables/ResourceSelectable.cs | 86 - .../Directory.Build.props | 10 - .../ParsingTests.cs | 3084 ---------------- .../PatchManager.SassyPatching.Tests.csproj | 23 - .../Usings.cs | 18 - .../Validators/ArgumentValidator.cs | 31 - .../RunAtStageAttributeValidator.cs | 17 - .../Validators/BlockValidator.cs | 44 - .../Validators/CallArgumentValidator.cs | 26 - .../Validators/Expressions/BinaryValidator.cs | 23 - .../Validators/Expressions/ListValidator.cs | 43 - .../Expressions/MemberCallValidator.cs | 31 - .../Validators/Expressions/ObjectValidator.cs | 43 - .../Expressions/SimpleCallValidator.cs | 27 - .../Expressions/TernaryValidator.cs | 28 - .../Validators/Expressions/UnaryValidator.cs | 18 - .../Validators/Expressions/ValueValidator.cs | 93 - .../Expressions/VariableReferenceValidator.cs | 20 - .../Validators/FalseValidator.cs | 14 - .../Validators/KeyValueValidator.cs | 22 - .../Validators/ParseValidator.cs | 35 - .../Validators/PatchValidator.cs | 46 - .../Selectors/ChildSelectorValidator.cs | 20 - .../Selectors/ClassSelectorValidator.cs | 17 - .../Selectors/CombinationSelectorValidator.cs | 41 - .../Selectors/ElementSelectorValidator.cs | 17 - .../IntersectionSelectorValidator.cs | 39 - .../Selectors/NameSelectorValidator.cs | 17 - .../Selectors/RulesetSelectorValidator.cs | 17 - .../Selectors/WildcardSelectorValidator.cs | 13 - .../WithoutClassSelectorValidator.cs | 17 - .../Selectors/WithoutNameSelectorValidator.cs | 17 - .../Statements/ConditionalValidator.cs | 34 - .../FunctionLevel/ReturnValidator.cs | 20 - .../Statements/SelectionBlockValidator.cs | 32 - .../SelectionLevel/DeleteValueValidator.cs | 13 - .../SelectionLevel/FieldValidator.cs | 32 - .../SelectionLevel/MergeValueValidator.cs | 17 - .../SelectionLevel/MixinIncludeValidator.cs | 30 - .../SelectionLevel/SetValueValidator.cs | 21 - .../Statements/TopLevel/FunctionValidator.cs | 36 - .../Statements/TopLevel/ImportValidator.cs | 21 - .../Statements/TopLevel/MixinValidator.cs | 35 - .../VariableDeclarationValidator.cs | 26 - .../Attributes/PatcherRulesetAttribute.cs | 38 - .../Attributes/SassyConstantAttribute.cs | 11 - .../Attributes/SassyLibraryAttribute.cs | 31 - .../Attributes/SassyMethodAttribute.cs | 26 - .../Attributes/SassyNameAttribute.cs | 11 - .../Attributes/VarArgsAttribute.cs | 10 - .../BaseSelectable.cs | 70 - .../Builtins/ConfigBuiltins.cs | 18 - .../Builtins/DebugBuiltins.cs | 34 - .../Builtins/DictionaryBuiltins.cs | 54 - .../Builtins/FunctionalBuiltins.cs | 78 - .../Builtins/ListBuiltins.cs | 232 -- .../Builtins/MathBuiltins.cs | 121 - .../Builtins/MetaBuiltins.cs | 18 - .../Builtins/ReflectionBuiltins.cs | 23 - .../Builtins/StringBuiltins.cs | 42 - .../Builtins/TypeConversion.cs | 87 - src/PatchManager.SassyPatching/Coordinate.cs | 19 - src/PatchManager.SassyPatching/DataValue.cs | 1309 ------- .../BinaryExpressionTypeException.cs | 11 - .../Exceptions/DataValueOperationException.cs | 5 - .../DictionaryKeyNotFoundException.cs | 11 - .../Exceptions/FunctionReturnException.cs | 11 - .../Exceptions/ImportException.cs | 6 - .../Exceptions/IncorrectTypeException.cs | 11 - .../Exceptions/InterpolationException.cs | 6 - .../Exceptions/InterpreterException.cs | 17 - .../InvalidVariableReferenceException.cs | 11 - .../Exceptions/InvocationException.cs | 11 - .../ListIndexOutOfRangeException.cs | 8 - .../Exceptions/NotModifiableException.cs | 12 - .../Exceptions/TypeConversionException.cs | 11 - .../Exceptions/UnaryTypeException.cs | 11 - .../Execution/BoundPatchFunction.cs | 27 - .../Execution/Environment.cs | 95 - .../Execution/GlobalEnvironment.cs | 71 - .../Execution/ManagedPatchFunction.cs | 153 - .../Execution/ManagedPatchLibrary.cs | 42 - .../Execution/PatchArgument.cs | 19 - .../Execution/PatchFunction.cs | 15 - .../Execution/PatchLibrary.cs | 13 - .../Execution/PatchMixin.cs | 87 - .../Execution/SassyGenerator.cs | 51 - .../Execution/SassyPatchClosure.cs | 81 - .../Execution/SassyPatchFunction.cs | 81 - .../Execution/SassyPatchLibrary.cs | 18 - .../Execution/SassyTextPatcher.cs | 62 - .../Execution/SelectableWithEnvironment.cs | 19 - .../Execution/Stage.cs | 14 - .../Execution/Universe.cs | 467 --- .../Interfaces/IModifiable.cs | 37 - .../Interfaces/INewAsset.cs | 13 - .../Interfaces/IPatcherRuleSet.cs | 33 - .../Interfaces/ISelectable.cs | 70 - .../Modifiables/CustomJTokenModifiable.cs | 107 - .../Modifiables/JTokenModifiable.cs | 86 - .../NewAssets/NewGenericAsset.cs | 34 - .../Nodes/Argument.cs | 31 - .../Nodes/Attributes/NewAttribute.cs | 9 - .../RequireExpressions/RequireAnd.cs | 18 - .../RequireExpressions/RequireExpression.cs | 16 - .../RequireExpressions/RequireGuid.cs | 12 - .../RequireExpressions/RequireNot.cs | 11 - .../RequireExpressions/RequireOr.cs | 18 - .../Nodes/Attributes/RequireModAttribute.cs | 12 - .../Nodes/Attributes/RunAtStageAttribute.cs | 17 - .../Nodes/Attributes/SelectorAttribute.cs | 18 - src/PatchManager.SassyPatching/Nodes/Block.cs | 46 - .../Nodes/CallArgument.cs | 53 - .../Nodes/ErrorNode.cs | 25 - .../Nodes/Expressions/Binary/Add.cs | 29 - .../Nodes/Expressions/Binary/And.cs | 18 - .../Nodes/Expressions/Binary/Binary.cs | 43 - .../Nodes/Expressions/Binary/Divide.cs | 29 - .../Nodes/Expressions/Binary/EqualTo.cs | 18 - .../Nodes/Expressions/Binary/GreaterThan.cs | 30 - .../Expressions/Binary/GreaterThanEqual.cs | 29 - .../Nodes/Expressions/Binary/LesserThan.cs | 30 - .../Expressions/Binary/LesserThanEqual.cs | 28 - .../Nodes/Expressions/Binary/Multiply.cs | 32 - .../Nodes/Expressions/Binary/NotEqualTo.cs | 17 - .../Nodes/Expressions/Binary/Or.cs | 18 - .../Nodes/Expressions/Binary/Remainder.cs | 29 - .../Nodes/Expressions/Binary/Subscript.cs | 39 - .../Nodes/Expressions/Binary/Subtract.cs | 29 - .../Nodes/Expressions/Closure.cs | 30 - .../Nodes/Expressions/Expression.cs | 27 - .../Nodes/Expressions/ListNode.cs | 24 - .../Expressions/LocalVariableReference.cs | 25 - .../Nodes/Expressions/MemberCall.cs | 79 - .../Nodes/Expressions/ObjectNode.cs | 24 - .../Nodes/Expressions/SimpleCall.cs | 47 - .../Nodes/Expressions/Ternary.cs | 34 - .../Nodes/Expressions/Unary/Implicit.cs | 27 - .../Nodes/Expressions/Unary/ImplicitAdd.cs | 32 - .../Nodes/Expressions/Unary/ImplicitDivide.cs | 26 - .../Expressions/Unary/ImplicitMultiply.cs | 27 - .../Expressions/Unary/ImplicitSubtract.cs | 26 - .../Nodes/Expressions/Unary/Negate.cs | 25 - .../Nodes/Expressions/Unary/Not.cs | 14 - .../Nodes/Expressions/Unary/Positive.cs | 13 - .../Nodes/Expressions/Unary/Unary.cs | 29 - .../Nodes/Expressions/ValueNode.cs | 37 - .../Nodes/Expressions/VariableReference.cs | 33 - .../Nodes/Indexers/EverythingIndexer.cs | 3 - .../Nodes/Indexers/Indexer.cs | 18 - .../Nodes/Indexers/SingleIndexer.cs | 8 - .../Nodes/KeyValueNode.cs | 30 - src/PatchManager.SassyPatching/Nodes/Node.cs | 29 - .../Nodes/SassyPatch.cs | 28 - .../Nodes/Selectors/ChildSelector.cs | 54 - .../Nodes/Selectors/ClassCaptureSelector.cs | 60 - .../Nodes/Selectors/ClassSelector.cs | 39 - .../Nodes/Selectors/CombinationSelector.cs | 81 - .../Selectors/ElementAdditionSelector.cs | 68 - .../Nodes/Selectors/ElementSelector.cs | 54 - .../Nodes/Selectors/EnsureSelector.cs | 84 - .../Nodes/Selectors/IntersectionSelector.cs | 70 - .../Nodes/Selectors/NameSelector.cs | 39 - .../Nodes/Selectors/RulesetSelector.cs | 75 - .../Nodes/Selectors/Selector.cs | 48 - .../Nodes/Selectors/WildcardSelector.cs | 34 - .../Nodes/Selectors/WithoutClassSelector.cs | 39 - .../Nodes/Selectors/WithoutNameSelector.cs | 39 - .../Nodes/Statements/Conditional.cs | 79 - .../Nodes/Statements/Each.cs | 222 -- .../Nodes/Statements/For.cs | 346 -- .../Nodes/Statements/FunctionLevel/Return.cs | 26 - .../Nodes/Statements/SelectionBlock.cs | 201 -- .../Statements/SelectionLevel/DeleteValue.cs | 30 - .../Nodes/Statements/SelectionLevel/Field.cs | 160 - .../SelectionLevel/ISelectionAction.cs | 19 - .../Statements/SelectionLevel/MergeValue.cs | 56 - .../SelectionLevel/MixinBlockInclude.cs | 61 - .../Statements/SelectionLevel/MixinInclude.cs | 51 - .../Statements/SelectionLevel/MixinSlot.cs | 33 - .../Statements/SelectionLevel/SetValue.cs | 44 - .../Statements/TopLevel/ConfigCreation.cs | 37 - .../Nodes/Statements/TopLevel/ConfigUpdate.cs | 31 - .../Nodes/Statements/TopLevel/Function.cs | 38 - .../Nodes/Statements/TopLevel/Import.cs | 48 - .../Nodes/Statements/TopLevel/Mixin.cs | 35 - .../Statements/TopLevel/PatchDeclaration.cs | 22 - .../Statements/TopLevel/StageDefinition.cs | 107 - .../TopLevel/StageDefinitionAttribute.cs | 17 - .../Nodes/Statements/VariableDeclaration.cs | 164 - .../Nodes/Statements/While.cs | 56 - .../PatchManager.SassyPatching.csproj | 10 - .../Selectables/JTokenSelectable.cs | 130 - .../SelectionUtilities.cs | 19 - src/PatchManager.SassyPatching/Transformer.cs | 820 ----- .../Utility/Extensions.cs | 129 - .../Utility/GlobalUsings.cs | 1 - .../Modifiables/DiscoverablesModifiable.cs | 32 - .../Modifiables/ExperimentModifiable.cs | 36 - .../Modifiables/RegionsModifiable.cs | 33 - .../Modifiables/ScienceModifiable.cs | 33 - .../PatchManager.Science.csproj | 11 - .../Rulesets/DiscoverablesRuleset.cs | 38 - .../Rulesets/ExperimentRuleset.cs | 38 - .../Rulesets/RegionsRuleset.cs | 38 - .../Rulesets/ScienceRuleset.cs | 29 - src/PatchManager.Science/ScienceModule.cs | 12 - .../Selectables/DiscoverablesSelectable.cs | 125 - .../Selectables/ExperimentSelectable.cs | 111 - .../Selectables/RegionsSelectable.cs | 124 - .../Selectables/ScienceSelectable.cs | 105 - src/PatchManager.Shared/Extensions.cs | 128 - .../Interfaces/ITextAssetGenerator.cs | 20 - .../Interfaces/ITextPatcher.cs | 21 - src/PatchManager.Shared/Logging.cs | 86 - src/PatchManager.Shared/Modules/BaseModule.cs | 35 - src/PatchManager.Shared/Modules/IModule.cs | 42 - .../Modules/ModuleManager.cs | 70 - .../PatchManager.Shared.csproj | 12 - .../Properties/AssemblyInfo.cs | 3 - src/PatchManager/PatchManager.csproj | 21 - src/PatchManager/PatchManagerPlugin.cs | 131 - 978 files changed, 24756 insertions(+), 19321 deletions(-) create mode 100644 .idea/.idea.PatchManager/.idea/.gitignore create mode 100644 .idea/.idea.PatchManager/.idea/.name create mode 100644 Directory.Build.props.meta create mode 100644 Editor.meta create mode 100644 Editor/PatchImporter.cs create mode 100644 Editor/PatchImporter.cs.meta create mode 100644 Editor/Tests.meta create mode 100644 Editor/Tests/ParsingTests.cs create mode 100644 Editor/Tests/ParsingTests.cs.meta create mode 100644 Editor/Tests/Validators.meta create mode 100644 Editor/Tests/Validators/ArgumentValidator.cs create mode 100644 Editor/Tests/Validators/ArgumentValidator.cs.meta create mode 100644 Editor/Tests/Validators/Attributes.meta create mode 100644 Editor/Tests/Validators/Attributes/RunAtStageAttributeValidator.cs create mode 100644 Editor/Tests/Validators/Attributes/RunAtStageAttributeValidator.cs.meta create mode 100644 Editor/Tests/Validators/BlockValidator.cs create mode 100644 Editor/Tests/Validators/BlockValidator.cs.meta create mode 100644 Editor/Tests/Validators/CallArgumentValidator.cs create mode 100644 Editor/Tests/Validators/CallArgumentValidator.cs.meta create mode 100644 Editor/Tests/Validators/Expressions.meta create mode 100644 Editor/Tests/Validators/Expressions/BinaryValidator.cs create mode 100644 Editor/Tests/Validators/Expressions/BinaryValidator.cs.meta create mode 100644 Editor/Tests/Validators/Expressions/ListValidator.cs create mode 100644 Editor/Tests/Validators/Expressions/ListValidator.cs.meta create mode 100644 Editor/Tests/Validators/Expressions/MemberCallValidator.cs create mode 100644 Editor/Tests/Validators/Expressions/MemberCallValidator.cs.meta create mode 100644 Editor/Tests/Validators/Expressions/ObjectValidator.cs create mode 100644 Editor/Tests/Validators/Expressions/ObjectValidator.cs.meta create mode 100644 Editor/Tests/Validators/Expressions/SimpleCallValidator.cs create mode 100644 Editor/Tests/Validators/Expressions/SimpleCallValidator.cs.meta create mode 100644 Editor/Tests/Validators/Expressions/TernaryValidator.cs create mode 100644 Editor/Tests/Validators/Expressions/TernaryValidator.cs.meta create mode 100644 Editor/Tests/Validators/Expressions/UnaryValidator.cs create mode 100644 Editor/Tests/Validators/Expressions/UnaryValidator.cs.meta create mode 100644 Editor/Tests/Validators/Expressions/ValueValidator.cs create mode 100644 Editor/Tests/Validators/Expressions/ValueValidator.cs.meta create mode 100644 Editor/Tests/Validators/Expressions/VariableReferenceValidator.cs create mode 100644 Editor/Tests/Validators/Expressions/VariableReferenceValidator.cs.meta create mode 100644 Editor/Tests/Validators/FalseValidator.cs create mode 100644 Editor/Tests/Validators/FalseValidator.cs.meta create mode 100644 Editor/Tests/Validators/KeyValueValidator.cs create mode 100644 Editor/Tests/Validators/KeyValueValidator.cs.meta create mode 100644 Editor/Tests/Validators/ParseValidator.cs create mode 100644 Editor/Tests/Validators/ParseValidator.cs.meta create mode 100644 Editor/Tests/Validators/PatchValidator.cs create mode 100644 Editor/Tests/Validators/PatchValidator.cs.meta create mode 100644 Editor/Tests/Validators/Selectors.meta create mode 100644 Editor/Tests/Validators/Selectors/ChildSelectorValidator.cs create mode 100644 Editor/Tests/Validators/Selectors/ChildSelectorValidator.cs.meta create mode 100644 Editor/Tests/Validators/Selectors/ClassSelectorValidator.cs create mode 100644 Editor/Tests/Validators/Selectors/ClassSelectorValidator.cs.meta create mode 100644 Editor/Tests/Validators/Selectors/CombinationSelectorValidator.cs create mode 100644 Editor/Tests/Validators/Selectors/CombinationSelectorValidator.cs.meta create mode 100644 Editor/Tests/Validators/Selectors/ElementSelectorValidator.cs create mode 100644 Editor/Tests/Validators/Selectors/ElementSelectorValidator.cs.meta create mode 100644 Editor/Tests/Validators/Selectors/IntersectionSelectorValidator.cs create mode 100644 Editor/Tests/Validators/Selectors/IntersectionSelectorValidator.cs.meta create mode 100644 Editor/Tests/Validators/Selectors/NameSelectorValidator.cs create mode 100644 Editor/Tests/Validators/Selectors/NameSelectorValidator.cs.meta create mode 100644 Editor/Tests/Validators/Selectors/RulesetSelectorValidator.cs create mode 100644 Editor/Tests/Validators/Selectors/RulesetSelectorValidator.cs.meta create mode 100644 Editor/Tests/Validators/Selectors/WildcardSelectorValidator.cs create mode 100644 Editor/Tests/Validators/Selectors/WildcardSelectorValidator.cs.meta create mode 100644 Editor/Tests/Validators/Selectors/WithoutClassSelectorValidator.cs create mode 100644 Editor/Tests/Validators/Selectors/WithoutClassSelectorValidator.cs.meta create mode 100644 Editor/Tests/Validators/Selectors/WithoutNameSelectorValidator.cs create mode 100644 Editor/Tests/Validators/Selectors/WithoutNameSelectorValidator.cs.meta create mode 100644 Editor/Tests/Validators/Statements.meta create mode 100644 Editor/Tests/Validators/Statements/ConditionalValidator.cs create mode 100644 Editor/Tests/Validators/Statements/ConditionalValidator.cs.meta create mode 100644 Editor/Tests/Validators/Statements/FunctionLevel.meta create mode 100644 Editor/Tests/Validators/Statements/FunctionLevel/ReturnValidator.cs create mode 100644 Editor/Tests/Validators/Statements/FunctionLevel/ReturnValidator.cs.meta create mode 100644 Editor/Tests/Validators/Statements/SelectionBlockValidator.cs create mode 100644 Editor/Tests/Validators/Statements/SelectionBlockValidator.cs.meta create mode 100644 Editor/Tests/Validators/Statements/SelectionLevel.meta create mode 100644 Editor/Tests/Validators/Statements/SelectionLevel/DeleteValueValidator.cs create mode 100644 Editor/Tests/Validators/Statements/SelectionLevel/DeleteValueValidator.cs.meta create mode 100644 Editor/Tests/Validators/Statements/SelectionLevel/FieldValidator.cs create mode 100644 Editor/Tests/Validators/Statements/SelectionLevel/FieldValidator.cs.meta create mode 100644 Editor/Tests/Validators/Statements/SelectionLevel/MergeValueValidator.cs create mode 100644 Editor/Tests/Validators/Statements/SelectionLevel/MergeValueValidator.cs.meta create mode 100644 Editor/Tests/Validators/Statements/SelectionLevel/MixinIncludeValidator.cs create mode 100644 Editor/Tests/Validators/Statements/SelectionLevel/MixinIncludeValidator.cs.meta create mode 100644 Editor/Tests/Validators/Statements/SelectionLevel/SetValueValidator.cs create mode 100644 Editor/Tests/Validators/Statements/SelectionLevel/SetValueValidator.cs.meta create mode 100644 Editor/Tests/Validators/Statements/TopLevel.meta create mode 100644 Editor/Tests/Validators/Statements/TopLevel/FunctionValidator.cs create mode 100644 Editor/Tests/Validators/Statements/TopLevel/FunctionValidator.cs.meta create mode 100644 Editor/Tests/Validators/Statements/TopLevel/ImportValidator.cs create mode 100644 Editor/Tests/Validators/Statements/TopLevel/ImportValidator.cs.meta create mode 100644 Editor/Tests/Validators/Statements/TopLevel/MixinValidator.cs create mode 100644 Editor/Tests/Validators/Statements/TopLevel/MixinValidator.cs.meta create mode 100644 Editor/Tests/Validators/Statements/VariableDeclarationValidator.cs create mode 100644 Editor/Tests/Validators/Statements/VariableDeclarationValidator.cs.meta create mode 100644 LICENSE.meta create mode 100644 Package.nuspec.meta create mode 100644 PatchManager.sln.DotSettings.meta create mode 100644 PatchManager.sln.meta create mode 100644 README.md.meta create mode 100644 Runtime.meta create mode 100644 Runtime/Core.meta create mode 100644 Runtime/Core/Assets.meta create mode 100644 Runtime/Core/Assets/ArchiveResourceLocator.cs create mode 100644 Runtime/Core/Assets/ArchiveResourceLocator.cs.meta create mode 100644 Runtime/Core/Assets/ArchiveResourceProvider.cs create mode 100644 Runtime/Core/Assets/ArchiveResourceProvider.cs.meta create mode 100644 Runtime/Core/Assets/Locators.cs create mode 100644 Runtime/Core/Assets/Locators.cs.meta create mode 100644 Runtime/Core/Assets/PatchingManager.cs create mode 100644 Runtime/Core/Assets/PatchingManager.cs.meta create mode 100644 Runtime/Core/Cache.meta create mode 100644 Runtime/Core/Cache/Archive.cs create mode 100644 Runtime/Core/Cache/Archive.cs.meta create mode 100644 Runtime/Core/Cache/CacheManager.cs create mode 100644 Runtime/Core/Cache/CacheManager.cs.meta create mode 100644 Runtime/Core/Cache/Json.meta create mode 100644 Runtime/Core/Cache/Json/CacheEntry.cs create mode 100644 Runtime/Core/Cache/Json/CacheEntry.cs.meta create mode 100644 Runtime/Core/Cache/Json/Inventory.cs create mode 100644 Runtime/Core/Cache/Json/Inventory.cs.meta create mode 100644 Runtime/Core/Cache/Json/PatchHashes.cs create mode 100644 Runtime/Core/Cache/Json/PatchHashes.cs.meta create mode 100644 Runtime/Core/CoreModule.cs create mode 100644 Runtime/Core/CoreModule.cs.meta create mode 100644 Runtime/Core/Flow.meta create mode 100644 Runtime/Core/Flow/FlowAction.cs create mode 100644 Runtime/Core/Flow/FlowAction.cs.meta create mode 100644 Runtime/Core/Flow/FlowManager.cs create mode 100644 Runtime/Core/Flow/FlowManager.cs.meta create mode 100644 Runtime/Core/Utility.meta create mode 100644 Runtime/Core/Utility/Hash.cs create mode 100644 Runtime/Core/Utility/Hash.cs.meta create mode 100644 Runtime/Core/Utility/Versions.cs create mode 100644 Runtime/Core/Utility/Versions.cs.meta create mode 100644 Runtime/Generic.meta create mode 100644 Runtime/Generic/GenericModule.cs create mode 100644 Runtime/Generic/GenericModule.cs.meta create mode 100644 Runtime/Generic/SassyPatching.meta create mode 100644 Runtime/Generic/SassyPatching/Rulesets.meta create mode 100644 Runtime/Generic/SassyPatching/Rulesets/JsonRuleset.cs create mode 100644 Runtime/Generic/SassyPatching/Rulesets/JsonRuleset.cs.meta create mode 100644 Runtime/Missions.meta create mode 100644 Runtime/Missions/Builtins.meta create mode 100644 Runtime/Missions/Builtins/MissionsBuiltins.cs create mode 100644 Runtime/Missions/Builtins/MissionsBuiltins.cs.meta create mode 100644 Runtime/Missions/MissionsModule.cs create mode 100644 Runtime/Missions/MissionsModule.cs.meta create mode 100644 Runtime/Missions/MissionsTypes.cs create mode 100644 Runtime/Missions/MissionsTypes.cs.meta create mode 100644 Runtime/Missions/Modifiables.meta create mode 100644 Runtime/Missions/Modifiables/MissionModifiable.cs create mode 100644 Runtime/Missions/Modifiables/MissionModifiable.cs.meta create mode 100644 Runtime/Missions/Rulesets.meta create mode 100644 Runtime/Missions/Rulesets/MissionRuleset.cs create mode 100644 Runtime/Missions/Rulesets/MissionRuleset.cs.meta create mode 100644 Runtime/Missions/Selectables.meta create mode 100644 Runtime/Missions/Selectables/ActionsSelectable.cs create mode 100644 Runtime/Missions/Selectables/ActionsSelectable.cs.meta create mode 100644 Runtime/Missions/Selectables/ConditionSetSelectable.cs create mode 100644 Runtime/Missions/Selectables/ConditionSetSelectable.cs.meta create mode 100644 Runtime/Missions/Selectables/ContentBranchSelectable.cs create mode 100644 Runtime/Missions/Selectables/ContentBranchSelectable.cs.meta create mode 100644 Runtime/Missions/Selectables/ContentBranchesSelectable.cs create mode 100644 Runtime/Missions/Selectables/ContentBranchesSelectable.cs.meta create mode 100644 Runtime/Missions/Selectables/MissionRewardSelectable.cs create mode 100644 Runtime/Missions/Selectables/MissionRewardSelectable.cs.meta create mode 100644 Runtime/Missions/Selectables/MissionSelectable.cs create mode 100644 Runtime/Missions/Selectables/MissionSelectable.cs.meta create mode 100644 Runtime/Missions/Selectables/StageSelectable.cs create mode 100644 Runtime/Missions/Selectables/StageSelectable.cs.meta create mode 100644 Runtime/Missions/Selectables/StagesSelectable.cs create mode 100644 Runtime/Missions/Selectables/StagesSelectable.cs.meta create mode 100644 Runtime/Parts.meta create mode 100644 Runtime/Parts/Attributes.meta create mode 100644 Runtime/Parts/Attributes/ModuleDataAdapterAttribute.cs create mode 100644 Runtime/Parts/Attributes/ModuleDataAdapterAttribute.cs.meta create mode 100644 Runtime/Parts/Builtins.meta create mode 100644 Runtime/Parts/Builtins/PartsBuiltins.cs create mode 100644 Runtime/Parts/Builtins/PartsBuiltins.cs.meta create mode 100644 Runtime/Parts/Modifiables.meta create mode 100644 Runtime/Parts/Modifiables/PartModifiable.cs create mode 100644 Runtime/Parts/Modifiables/PartModifiable.cs.meta create mode 100644 Runtime/Parts/PartsModule.cs create mode 100644 Runtime/Parts/PartsModule.cs.meta create mode 100644 Runtime/Parts/PartsUtilities.cs create mode 100644 Runtime/Parts/PartsUtilities.cs.meta create mode 100644 Runtime/Parts/Patchers.meta create mode 100644 Runtime/Parts/Patchers/OABUtilsPatcher.cs create mode 100644 Runtime/Parts/Patchers/OABUtilsPatcher.cs.meta create mode 100644 Runtime/Parts/Patchers/PartModuleLoadPatcher.cs create mode 100644 Runtime/Parts/Patchers/PartModuleLoadPatcher.cs.meta create mode 100644 Runtime/Parts/Patchers/UpdateSavedVesselPartDefinitions.cs create mode 100644 Runtime/Parts/Patchers/UpdateSavedVesselPartDefinitions.cs.meta create mode 100644 Runtime/Parts/Rulesets.meta create mode 100644 Runtime/Parts/Rulesets/PartsRuleset.cs create mode 100644 Runtime/Parts/Rulesets/PartsRuleset.cs.meta create mode 100644 Runtime/Parts/Selectables.meta create mode 100644 Runtime/Parts/Selectables/DataEngineSelectable.cs create mode 100644 Runtime/Parts/Selectables/DataEngineSelectable.cs.meta create mode 100644 Runtime/Parts/Selectables/ModuleSelectable.cs create mode 100644 Runtime/Parts/Selectables/ModuleSelectable.cs.meta create mode 100644 Runtime/Parts/Selectables/PartSelectable.cs create mode 100644 Runtime/Parts/Selectables/PartSelectable.cs.meta create mode 100644 Runtime/Parts/Selectables/ResourceContainerSelectable.cs create mode 100644 Runtime/Parts/Selectables/ResourceContainerSelectable.cs.meta create mode 100644 Runtime/Parts/Selectables/ResourceContainersSelectable.cs create mode 100644 Runtime/Parts/Selectables/ResourceContainersSelectable.cs.meta create mode 100644 Runtime/PatchManager.Resources.meta create mode 100644 Runtime/PatchManager.Resources/NonStageableResourcesUIController.cs create mode 100644 Runtime/PatchManager.Resources/NonStageableResourcesUIController.cs.meta create mode 100644 Runtime/PatchManager.Resources/ResourcesModule.cs create mode 100644 Runtime/PatchManager.Resources/ResourcesModule.cs.meta create mode 100644 Runtime/PatchManager.Resources/Rulesets.meta create mode 100644 Runtime/PatchManager.Resources/Rulesets/ResourceRuleset.cs create mode 100644 Runtime/PatchManager.Resources/Rulesets/ResourceRuleset.cs.meta create mode 100644 Runtime/PatchManager.Resources/Rulesets/ResourceUnitRuleset.cs create mode 100644 Runtime/PatchManager.Resources/Rulesets/ResourceUnitRuleset.cs.meta create mode 100644 Runtime/PatchManager.Resources/Selectables.meta create mode 100644 Runtime/PatchManager.Resources/Selectables/RecipeSelectable.cs create mode 100644 Runtime/PatchManager.Resources/Selectables/RecipeSelectable.cs.meta create mode 100644 Runtime/PatchManager.Resources/Selectables/ResourceSelectable.cs create mode 100644 Runtime/PatchManager.Resources/Selectables/ResourceSelectable.cs.meta create mode 100644 Runtime/PatchManager.cs create mode 100644 Runtime/PatchManager.cs.meta create mode 100644 Runtime/Planets.meta create mode 100644 Runtime/Planets/Shoemaker.meta rename {src/PatchManager => Runtime/Planets/Shoemaker}/Directory.Build.targets (68%) create mode 100644 Runtime/Planets/Shoemaker/Directory.Build.targets.meta create mode 100644 Runtime/Planets/Shoemaker/Modifiables.meta create mode 100644 Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs create mode 100644 Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs create mode 100644 Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs create mode 100644 Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs create mode 100644 Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs.meta create mode 100644 Runtime/Planets/Shoemaker/OverrideManager.cs create mode 100644 Runtime/Planets/Shoemaker/OverrideManager.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Overrides.meta create mode 100644 Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs create mode 100644 Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs create mode 100644 Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Overrides/IOverride.cs create mode 100644 Runtime/Planets/Shoemaker/Overrides/IOverride.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs create mode 100644 Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Patches.meta create mode 100644 Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs create mode 100644 Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs create mode 100644 Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs create mode 100644 Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs create mode 100644 Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs.meta create mode 100644 Runtime/Planets/Shoemaker/PlanetsModule.cs create mode 100644 Runtime/Planets/Shoemaker/PlanetsModule.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Rulesets.meta create mode 100644 Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs create mode 100644 Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs create mode 100644 Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs create mode 100644 Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs create mode 100644 Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Selectables.meta create mode 100644 Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs create mode 100644 Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs create mode 100644 Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs create mode 100644 Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs create mode 100644 Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Shoemaker.csproj create mode 100644 Runtime/Planets/Shoemaker/Shoemaker.csproj.meta create mode 100644 Runtime/Planets/Shoemaker/Utility.meta create mode 100644 Runtime/Planets/Shoemaker/Utility/Extensions.cs create mode 100644 Runtime/Planets/Shoemaker/Utility/Extensions.cs.meta create mode 100644 Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs create mode 100644 Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs.meta create mode 100644 Runtime/Planets/Shoemaker/swinfo.json create mode 100644 Runtime/Planets/Shoemaker/swinfo.json.meta create mode 100644 Runtime/SassyPatching.meta create mode 100644 Runtime/SassyPatching/Attributes.meta create mode 100644 Runtime/SassyPatching/Attributes/PatcherRulesetAttribute.cs create mode 100644 Runtime/SassyPatching/Attributes/PatcherRulesetAttribute.cs.meta create mode 100644 Runtime/SassyPatching/Attributes/SassyConstantAttribute.cs create mode 100644 Runtime/SassyPatching/Attributes/SassyConstantAttribute.cs.meta create mode 100644 Runtime/SassyPatching/Attributes/SassyLibraryAttribute.cs create mode 100644 Runtime/SassyPatching/Attributes/SassyLibraryAttribute.cs.meta create mode 100644 Runtime/SassyPatching/Attributes/SassyMethodAttribute.cs create mode 100644 Runtime/SassyPatching/Attributes/SassyMethodAttribute.cs.meta create mode 100644 Runtime/SassyPatching/Attributes/SassyNameAttribute.cs create mode 100644 Runtime/SassyPatching/Attributes/SassyNameAttribute.cs.meta create mode 100644 Runtime/SassyPatching/Attributes/VarArgsAttribute.cs create mode 100644 Runtime/SassyPatching/Attributes/VarArgsAttribute.cs.meta create mode 100644 Runtime/SassyPatching/BaseSelectable.cs create mode 100644 Runtime/SassyPatching/BaseSelectable.cs.meta create mode 100644 Runtime/SassyPatching/Builtins.meta create mode 100644 Runtime/SassyPatching/Builtins/ConfigBuiltins.cs create mode 100644 Runtime/SassyPatching/Builtins/ConfigBuiltins.cs.meta create mode 100644 Runtime/SassyPatching/Builtins/DebugBuiltins.cs create mode 100644 Runtime/SassyPatching/Builtins/DebugBuiltins.cs.meta create mode 100644 Runtime/SassyPatching/Builtins/DictionaryBuiltins.cs create mode 100644 Runtime/SassyPatching/Builtins/DictionaryBuiltins.cs.meta create mode 100644 Runtime/SassyPatching/Builtins/FunctionalBuiltins.cs create mode 100644 Runtime/SassyPatching/Builtins/FunctionalBuiltins.cs.meta create mode 100644 Runtime/SassyPatching/Builtins/ListBuiltins.cs create mode 100644 Runtime/SassyPatching/Builtins/ListBuiltins.cs.meta create mode 100644 Runtime/SassyPatching/Builtins/MathBuiltins.cs create mode 100644 Runtime/SassyPatching/Builtins/MathBuiltins.cs.meta create mode 100644 Runtime/SassyPatching/Builtins/MetaBuiltins.cs create mode 100644 Runtime/SassyPatching/Builtins/MetaBuiltins.cs.meta create mode 100644 Runtime/SassyPatching/Builtins/ReflectionBuiltins.cs create mode 100644 Runtime/SassyPatching/Builtins/ReflectionBuiltins.cs.meta create mode 100644 Runtime/SassyPatching/Builtins/StringBuiltins.cs create mode 100644 Runtime/SassyPatching/Builtins/StringBuiltins.cs.meta create mode 100644 Runtime/SassyPatching/Builtins/TypeConversion.cs create mode 100644 Runtime/SassyPatching/Builtins/TypeConversion.cs.meta create mode 100644 Runtime/SassyPatching/Coordinate.cs create mode 100644 Runtime/SassyPatching/Coordinate.cs.meta create mode 100644 Runtime/SassyPatching/DataValue.cs create mode 100644 Runtime/SassyPatching/DataValue.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions.meta create mode 100644 Runtime/SassyPatching/Exceptions/BinaryExpressionTypeException.cs create mode 100644 Runtime/SassyPatching/Exceptions/BinaryExpressionTypeException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/DataValueOperationException.cs create mode 100644 Runtime/SassyPatching/Exceptions/DataValueOperationException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/DictionaryKeyNotFoundException.cs create mode 100644 Runtime/SassyPatching/Exceptions/DictionaryKeyNotFoundException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/FunctionReturnException.cs create mode 100644 Runtime/SassyPatching/Exceptions/FunctionReturnException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/ImportException.cs create mode 100644 Runtime/SassyPatching/Exceptions/ImportException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/IncorrectTypeException.cs create mode 100644 Runtime/SassyPatching/Exceptions/IncorrectTypeException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/InterpolationException.cs create mode 100644 Runtime/SassyPatching/Exceptions/InterpolationException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/InterpreterException.cs create mode 100644 Runtime/SassyPatching/Exceptions/InterpreterException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/InvalidVariableReferenceException.cs create mode 100644 Runtime/SassyPatching/Exceptions/InvalidVariableReferenceException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/InvocationException.cs create mode 100644 Runtime/SassyPatching/Exceptions/InvocationException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/ListIndexOutOfRangeException.cs create mode 100644 Runtime/SassyPatching/Exceptions/ListIndexOutOfRangeException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/NotModifiableException.cs create mode 100644 Runtime/SassyPatching/Exceptions/NotModifiableException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/TypeConversionException.cs create mode 100644 Runtime/SassyPatching/Exceptions/TypeConversionException.cs.meta create mode 100644 Runtime/SassyPatching/Exceptions/UnaryTypeException.cs create mode 100644 Runtime/SassyPatching/Exceptions/UnaryTypeException.cs.meta create mode 100644 Runtime/SassyPatching/Execution.meta create mode 100644 Runtime/SassyPatching/Execution/BoundPatchFunction.cs create mode 100644 Runtime/SassyPatching/Execution/BoundPatchFunction.cs.meta create mode 100644 Runtime/SassyPatching/Execution/Environment.cs create mode 100644 Runtime/SassyPatching/Execution/Environment.cs.meta create mode 100644 Runtime/SassyPatching/Execution/GlobalEnvironment.cs create mode 100644 Runtime/SassyPatching/Execution/GlobalEnvironment.cs.meta create mode 100644 Runtime/SassyPatching/Execution/ManagedPatchFunction.cs create mode 100644 Runtime/SassyPatching/Execution/ManagedPatchFunction.cs.meta create mode 100644 Runtime/SassyPatching/Execution/ManagedPatchLibrary.cs create mode 100644 Runtime/SassyPatching/Execution/ManagedPatchLibrary.cs.meta create mode 100644 Runtime/SassyPatching/Execution/PatchArgument.cs create mode 100644 Runtime/SassyPatching/Execution/PatchArgument.cs.meta create mode 100644 Runtime/SassyPatching/Execution/PatchFunction.cs create mode 100644 Runtime/SassyPatching/Execution/PatchFunction.cs.meta create mode 100644 Runtime/SassyPatching/Execution/PatchLibrary.cs create mode 100644 Runtime/SassyPatching/Execution/PatchLibrary.cs.meta create mode 100644 Runtime/SassyPatching/Execution/PatchMixin.cs create mode 100644 Runtime/SassyPatching/Execution/PatchMixin.cs.meta create mode 100644 Runtime/SassyPatching/Execution/SassyGenerator.cs create mode 100644 Runtime/SassyPatching/Execution/SassyGenerator.cs.meta create mode 100644 Runtime/SassyPatching/Execution/SassyPatchClosure.cs create mode 100644 Runtime/SassyPatching/Execution/SassyPatchClosure.cs.meta create mode 100644 Runtime/SassyPatching/Execution/SassyPatchFunction.cs create mode 100644 Runtime/SassyPatching/Execution/SassyPatchFunction.cs.meta create mode 100644 Runtime/SassyPatching/Execution/SassyPatchLibrary.cs create mode 100644 Runtime/SassyPatching/Execution/SassyPatchLibrary.cs.meta create mode 100644 Runtime/SassyPatching/Execution/SassyTextPatcher.cs create mode 100644 Runtime/SassyPatching/Execution/SassyTextPatcher.cs.meta create mode 100644 Runtime/SassyPatching/Execution/SelectableWithEnvironment.cs create mode 100644 Runtime/SassyPatching/Execution/SelectableWithEnvironment.cs.meta create mode 100644 Runtime/SassyPatching/Execution/Stage.cs create mode 100644 Runtime/SassyPatching/Execution/Stage.cs.meta create mode 100644 Runtime/SassyPatching/Execution/Universe.cs create mode 100644 Runtime/SassyPatching/Execution/Universe.cs.meta create mode 100644 Runtime/SassyPatching/Interfaces.meta create mode 100644 Runtime/SassyPatching/Interfaces/IModifiable.cs create mode 100644 Runtime/SassyPatching/Interfaces/IModifiable.cs.meta create mode 100644 Runtime/SassyPatching/Interfaces/INewAsset.cs create mode 100644 Runtime/SassyPatching/Interfaces/INewAsset.cs.meta create mode 100644 Runtime/SassyPatching/Interfaces/IPatcherRuleSet.cs create mode 100644 Runtime/SassyPatching/Interfaces/IPatcherRuleSet.cs.meta create mode 100644 Runtime/SassyPatching/Interfaces/ISelectable.cs create mode 100644 Runtime/SassyPatching/Interfaces/ISelectable.cs.meta create mode 100644 Runtime/SassyPatching/Modifiables.meta create mode 100644 Runtime/SassyPatching/Modifiables/CustomJTokenModifiable.cs create mode 100644 Runtime/SassyPatching/Modifiables/CustomJTokenModifiable.cs.meta create mode 100644 Runtime/SassyPatching/Modifiables/JTokenModifiable.cs create mode 100644 Runtime/SassyPatching/Modifiables/JTokenModifiable.cs.meta create mode 100644 Runtime/SassyPatching/NewAssets.meta create mode 100644 Runtime/SassyPatching/NewAssets/NewGenericAsset.cs create mode 100644 Runtime/SassyPatching/NewAssets/NewGenericAsset.cs.meta create mode 100644 Runtime/SassyPatching/Nodes.meta create mode 100644 Runtime/SassyPatching/Nodes/Argument.cs create mode 100644 Runtime/SassyPatching/Nodes/Argument.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Attributes.meta create mode 100644 Runtime/SassyPatching/Nodes/Attributes/NewAttribute.cs create mode 100644 Runtime/SassyPatching/Nodes/Attributes/NewAttribute.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireExpressions.meta create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireAnd.cs create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireAnd.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireExpression.cs create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireExpression.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireGuid.cs create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireGuid.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireNot.cs create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireNot.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireOr.cs create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireOr.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireModAttribute.cs create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RequireModAttribute.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RunAtStageAttribute.cs create mode 100644 Runtime/SassyPatching/Nodes/Attributes/RunAtStageAttribute.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Attributes/SelectorAttribute.cs create mode 100644 Runtime/SassyPatching/Nodes/Attributes/SelectorAttribute.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Block.cs create mode 100644 Runtime/SassyPatching/Nodes/Block.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/CallArgument.cs create mode 100644 Runtime/SassyPatching/Nodes/CallArgument.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/ErrorNode.cs create mode 100644 Runtime/SassyPatching/Nodes/ErrorNode.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Add.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Add.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/And.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/And.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Binary.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Binary.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Divide.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Divide.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/EqualTo.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/EqualTo.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThan.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThan.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThanEqual.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThanEqual.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThan.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThan.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThanEqual.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThanEqual.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Multiply.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Multiply.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/NotEqualTo.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/NotEqualTo.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Or.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Or.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Remainder.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Remainder.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Subscript.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Subscript.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Subtract.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Binary/Subtract.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Closure.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Closure.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Expression.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Expression.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/ListNode.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/ListNode.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/LocalVariableReference.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/LocalVariableReference.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/MemberCall.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/MemberCall.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/ObjectNode.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/ObjectNode.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/SimpleCall.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/SimpleCall.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Ternary.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Ternary.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/Implicit.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/Implicit.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitAdd.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitAdd.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitDivide.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitDivide.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitMultiply.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitMultiply.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitSubtract.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitSubtract.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/Negate.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/Negate.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/Not.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/Not.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/Positive.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/Positive.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/Unary.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/Unary/Unary.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/ValueNode.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/ValueNode.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Expressions/VariableReference.cs create mode 100644 Runtime/SassyPatching/Nodes/Expressions/VariableReference.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Indexers.meta create mode 100644 Runtime/SassyPatching/Nodes/Indexers/EverythingIndexer.cs create mode 100644 Runtime/SassyPatching/Nodes/Indexers/EverythingIndexer.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Indexers/Indexer.cs create mode 100644 Runtime/SassyPatching/Nodes/Indexers/Indexer.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Indexers/SingleIndexer.cs create mode 100644 Runtime/SassyPatching/Nodes/Indexers/SingleIndexer.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/KeyValueNode.cs create mode 100644 Runtime/SassyPatching/Nodes/KeyValueNode.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Node.cs create mode 100644 Runtime/SassyPatching/Nodes/Node.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/SassyPatch.cs create mode 100644 Runtime/SassyPatching/Nodes/SassyPatch.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/ChildSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/ChildSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/ClassCaptureSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/ClassCaptureSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/ClassSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/ClassSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/CombinationSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/CombinationSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/ElementAdditionSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/ElementAdditionSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/ElementSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/ElementSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/EnsureSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/EnsureSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/IntersectionSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/IntersectionSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/NameSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/NameSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/RulesetSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/RulesetSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/Selector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/Selector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/WildcardSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/WildcardSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/WithoutClassSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/WithoutClassSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Selectors/WithoutNameSelector.cs create mode 100644 Runtime/SassyPatching/Nodes/Selectors/WithoutNameSelector.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/Conditional.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/Conditional.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/Each.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/Each.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/For.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/For.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/FunctionLevel.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/FunctionLevel/Return.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/FunctionLevel/Return.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionBlock.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionBlock.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/DeleteValue.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/DeleteValue.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/Field.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/Field.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/ISelectionAction.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/ISelectionAction.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MergeValue.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MergeValue.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinBlockInclude.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinBlockInclude.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinInclude.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinInclude.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinSlot.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinSlot.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/SetValue.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/SelectionLevel/SetValue.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigCreation.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigCreation.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigUpdate.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigUpdate.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/Function.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/Function.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/Import.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/Import.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/Mixin.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/Mixin.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/PatchDeclaration.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/PatchDeclaration.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinition.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinition.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinitionAttribute.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinitionAttribute.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/VariableDeclaration.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/VariableDeclaration.cs.meta create mode 100644 Runtime/SassyPatching/Nodes/Statements/While.cs create mode 100644 Runtime/SassyPatching/Nodes/Statements/While.cs.meta create mode 100644 Runtime/SassyPatching/SassyPatchGrammar.meta create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/gen.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/gen/sassy_lexer.interp (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.interp.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/gen/sassy_lexer.java (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.java.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/gen/sassy_lexer.tokens (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.tokens.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/sassy_lexer.cs (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.cs.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/sassy_lexer.g4 (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.g4.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/sassy_lexer.interp (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.interp.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/sassy_lexer.tokens (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.tokens.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/sassy_parser.cs (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.cs.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/sassy_parser.g4 (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.g4.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/sassy_parser.interp (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.interp.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/sassy_parser.tokens (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.tokens.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/sassy_parserBaseListener.cs (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/sassy_parserBaseListener.cs.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/sassy_parserBaseVisitor.cs (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/sassy_parserBaseVisitor.cs.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/sassy_parserListener.cs (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/sassy_parserListener.cs.meta rename {src/PatchManager.SassyPatching => Runtime/SassyPatching}/SassyPatchGrammar/sassy_parserVisitor.cs (100%) create mode 100644 Runtime/SassyPatching/SassyPatchGrammar/sassy_parserVisitor.cs.meta create mode 100644 Runtime/SassyPatching/Selectables.meta create mode 100644 Runtime/SassyPatching/Selectables/JTokenSelectable.cs create mode 100644 Runtime/SassyPatching/Selectables/JTokenSelectable.cs.meta create mode 100644 Runtime/SassyPatching/SelectionUtilities.cs create mode 100644 Runtime/SassyPatching/SelectionUtilities.cs.meta create mode 100644 Runtime/SassyPatching/Transformer.cs create mode 100644 Runtime/SassyPatching/Transformer.cs.meta create mode 100644 Runtime/SassyPatching/Utility.meta create mode 100644 Runtime/SassyPatching/Utility/Extensions.cs create mode 100644 Runtime/SassyPatching/Utility/Extensions.cs.meta create mode 100644 Runtime/Science.meta create mode 100644 Runtime/Science/Modifiables.meta create mode 100644 Runtime/Science/Modifiables/DiscoverablesModifiable.cs create mode 100644 Runtime/Science/Modifiables/DiscoverablesModifiable.cs.meta create mode 100644 Runtime/Science/Modifiables/ExperimentModifiable.cs create mode 100644 Runtime/Science/Modifiables/ExperimentModifiable.cs.meta create mode 100644 Runtime/Science/Modifiables/RegionsModifiable.cs create mode 100644 Runtime/Science/Modifiables/RegionsModifiable.cs.meta create mode 100644 Runtime/Science/Modifiables/ScienceModifiable.cs create mode 100644 Runtime/Science/Modifiables/ScienceModifiable.cs.meta create mode 100644 Runtime/Science/Rulesets.meta create mode 100644 Runtime/Science/Rulesets/DiscoverablesRuleset.cs create mode 100644 Runtime/Science/Rulesets/DiscoverablesRuleset.cs.meta create mode 100644 Runtime/Science/Rulesets/ExperimentRuleset.cs create mode 100644 Runtime/Science/Rulesets/ExperimentRuleset.cs.meta create mode 100644 Runtime/Science/Rulesets/RegionsRuleset.cs create mode 100644 Runtime/Science/Rulesets/RegionsRuleset.cs.meta create mode 100644 Runtime/Science/Rulesets/ScienceRuleset.cs create mode 100644 Runtime/Science/Rulesets/ScienceRuleset.cs.meta create mode 100644 Runtime/Science/ScienceModule.cs create mode 100644 Runtime/Science/ScienceModule.cs.meta create mode 100644 Runtime/Science/Selectables.meta create mode 100644 Runtime/Science/Selectables/DiscoverablesSelectable.cs create mode 100644 Runtime/Science/Selectables/DiscoverablesSelectable.cs.meta create mode 100644 Runtime/Science/Selectables/ExperimentSelectable.cs create mode 100644 Runtime/Science/Selectables/ExperimentSelectable.cs.meta create mode 100644 Runtime/Science/Selectables/RegionsSelectable.cs create mode 100644 Runtime/Science/Selectables/RegionsSelectable.cs.meta create mode 100644 Runtime/Science/Selectables/ScienceSelectable.cs create mode 100644 Runtime/Science/Selectables/ScienceSelectable.cs.meta create mode 100644 Runtime/Shared.meta create mode 100644 Runtime/Shared/Extensions.cs create mode 100644 Runtime/Shared/Extensions.cs.meta create mode 100644 Runtime/Shared/Interfaces.meta create mode 100644 Runtime/Shared/Interfaces/ITextAssetGenerator.cs create mode 100644 Runtime/Shared/Interfaces/ITextAssetGenerator.cs.meta create mode 100644 Runtime/Shared/Interfaces/ITextPatcher.cs create mode 100644 Runtime/Shared/Interfaces/ITextPatcher.cs.meta create mode 100644 Runtime/Shared/Logging.cs create mode 100644 Runtime/Shared/Logging.cs.meta create mode 100644 Runtime/Shared/Modules.meta create mode 100644 Runtime/Shared/Modules/BaseModule.cs create mode 100644 Runtime/Shared/Modules/BaseModule.cs.meta create mode 100644 Runtime/Shared/Modules/IModule.cs create mode 100644 Runtime/Shared/Modules/IModule.cs.meta create mode 100644 Runtime/Shared/Modules/ModuleManager.cs create mode 100644 Runtime/Shared/Modules/ModuleManager.cs.meta delete mode 100644 StandalonePatchTester/Program.cs delete mode 100644 StandalonePatchTester/StandalonePatchTester.csproj create mode 100644 images.meta create mode 100644 patch_tests.meta create mode 100644 patch_tests/json.meta create mode 100644 patch_tests/patches.meta create mode 100644 plugin_template.meta create mode 100644 scripts.meta delete mode 100644 src/PatchManager.Core/Assets/ArchiveResourceLocator.cs delete mode 100644 src/PatchManager.Core/Assets/ArchiveResourceProvider.cs delete mode 100644 src/PatchManager.Core/Assets/Locators.cs delete mode 100644 src/PatchManager.Core/Assets/PatchingManager.cs delete mode 100644 src/PatchManager.Core/Cache/Archive.cs delete mode 100644 src/PatchManager.Core/Cache/CacheManager.cs delete mode 100644 src/PatchManager.Core/Cache/Json/CacheEntry.cs delete mode 100644 src/PatchManager.Core/Cache/Json/Inventory.cs delete mode 100644 src/PatchManager.Core/Cache/Json/PatchHashes.cs delete mode 100644 src/PatchManager.Core/CoreModule.cs delete mode 100644 src/PatchManager.Core/Flow/FlowAction.cs delete mode 100644 src/PatchManager.Core/Flow/FlowManager.cs delete mode 100644 src/PatchManager.Core/Flow/IAction.cs delete mode 100644 src/PatchManager.Core/PatchManager.Core.csproj delete mode 100644 src/PatchManager.Core/PatchManager.Core.csproj.DotSettings delete mode 100644 src/PatchManager.Core/Patches/Preload/AssetProviderPatch.cs delete mode 100644 src/PatchManager.Core/Patches/Runtime/ExternalAssetsPatch.cs delete mode 100644 src/PatchManager.Core/Patches/Runtime/GameManagerPatch.cs delete mode 100644 src/PatchManager.Core/Patches/Runtime/LoadingBarPatch.cs delete mode 100644 src/PatchManager.Core/Utility/Hash.cs delete mode 100644 src/PatchManager.Core/Utility/Versions.cs delete mode 100644 src/PatchManager.Generic/GenericModule.cs delete mode 100644 src/PatchManager.Generic/PatchManager.Generic.csproj delete mode 100644 src/PatchManager.Generic/SassyPatching/Rulesets/JsonRuleset.cs delete mode 100644 src/PatchManager.Missions/Builtins/MissionsBuiltins.cs delete mode 100644 src/PatchManager.Missions/MissionsModule.cs delete mode 100644 src/PatchManager.Missions/MissionsTypes.cs delete mode 100644 src/PatchManager.Missions/Modifiables/MissionModifiable.cs delete mode 100644 src/PatchManager.Missions/PatchManager.Missions.csproj delete mode 100644 src/PatchManager.Missions/Rulesets/MissionRuleset.cs delete mode 100644 src/PatchManager.Missions/Selectables/ActionsSelectable.cs delete mode 100644 src/PatchManager.Missions/Selectables/ConditionSetSelectable.cs delete mode 100644 src/PatchManager.Missions/Selectables/ContentBranchSelectable.cs delete mode 100644 src/PatchManager.Missions/Selectables/ContentBranchesSelectable.cs delete mode 100644 src/PatchManager.Missions/Selectables/MissionRewardSelectable.cs delete mode 100644 src/PatchManager.Missions/Selectables/MissionSelectable.cs delete mode 100644 src/PatchManager.Missions/Selectables/StageSelectable.cs delete mode 100644 src/PatchManager.Missions/Selectables/StagesSelectable.cs delete mode 100644 src/PatchManager.Parts/Attributes/ModuleDataAdapterAttribute.cs delete mode 100644 src/PatchManager.Parts/Builtins/PartsBuiltins.cs delete mode 100644 src/PatchManager.Parts/Modifiables/PartModifiable.cs delete mode 100644 src/PatchManager.Parts/PartsModule.cs delete mode 100644 src/PatchManager.Parts/PartsUtilities.cs delete mode 100644 src/PatchManager.Parts/PatchManager.Parts.csproj delete mode 100644 src/PatchManager.Parts/Patchers/OABUtilsPatcher.cs delete mode 100644 src/PatchManager.Parts/Patchers/PartDataDeserializePatcher.cs delete mode 100644 src/PatchManager.Parts/Patchers/PartModuleLoadPatcher.cs delete mode 100644 src/PatchManager.Parts/Patchers/UpdateSavedVesselPartDefinitions.cs delete mode 100644 src/PatchManager.Parts/Rulesets/PartsRuleset.cs delete mode 100644 src/PatchManager.Parts/Selectables/DataEngineSelectable.cs delete mode 100644 src/PatchManager.Parts/Selectables/ModuleSelectable.cs delete mode 100644 src/PatchManager.Parts/Selectables/PartSelectable.cs delete mode 100644 src/PatchManager.Parts/Selectables/ResourceContainerSelectable.cs delete mode 100644 src/PatchManager.Parts/Selectables/ResourceContainersSelectable.cs delete mode 100644 src/PatchManager.Resources/PatchManager.Resources.csproj delete mode 100644 src/PatchManager.Resources/ResourcesModule.cs delete mode 100644 src/PatchManager.Resources/Rulesets/ResourceRuleset.cs delete mode 100644 src/PatchManager.Resources/Selectables/RecipeSelectable.cs delete mode 100644 src/PatchManager.Resources/Selectables/ResourceSelectable.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Directory.Build.props delete mode 100644 src/PatchManager.SassyPatching.Tests/ParsingTests.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/PatchManager.SassyPatching.Tests.csproj delete mode 100644 src/PatchManager.SassyPatching.Tests/Usings.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/ArgumentValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Attributes/RunAtStageAttributeValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/BlockValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/CallArgumentValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Expressions/BinaryValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Expressions/ListValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Expressions/MemberCallValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Expressions/ObjectValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Expressions/SimpleCallValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Expressions/TernaryValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Expressions/UnaryValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Expressions/ValueValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Expressions/VariableReferenceValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/FalseValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/KeyValueValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/ParseValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/PatchValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Selectors/ChildSelectorValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Selectors/ClassSelectorValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Selectors/CombinationSelectorValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Selectors/ElementSelectorValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Selectors/IntersectionSelectorValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Selectors/NameSelectorValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Selectors/RulesetSelectorValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Selectors/WildcardSelectorValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Selectors/WithoutClassSelectorValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Selectors/WithoutNameSelectorValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Statements/ConditionalValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Statements/FunctionLevel/ReturnValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionBlockValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/DeleteValueValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/FieldValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/MergeValueValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/MixinIncludeValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/SetValueValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Statements/TopLevel/FunctionValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Statements/TopLevel/ImportValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Statements/TopLevel/MixinValidator.cs delete mode 100644 src/PatchManager.SassyPatching.Tests/Validators/Statements/VariableDeclarationValidator.cs delete mode 100644 src/PatchManager.SassyPatching/Attributes/PatcherRulesetAttribute.cs delete mode 100644 src/PatchManager.SassyPatching/Attributes/SassyConstantAttribute.cs delete mode 100644 src/PatchManager.SassyPatching/Attributes/SassyLibraryAttribute.cs delete mode 100644 src/PatchManager.SassyPatching/Attributes/SassyMethodAttribute.cs delete mode 100644 src/PatchManager.SassyPatching/Attributes/SassyNameAttribute.cs delete mode 100644 src/PatchManager.SassyPatching/Attributes/VarArgsAttribute.cs delete mode 100644 src/PatchManager.SassyPatching/BaseSelectable.cs delete mode 100644 src/PatchManager.SassyPatching/Builtins/ConfigBuiltins.cs delete mode 100644 src/PatchManager.SassyPatching/Builtins/DebugBuiltins.cs delete mode 100644 src/PatchManager.SassyPatching/Builtins/DictionaryBuiltins.cs delete mode 100644 src/PatchManager.SassyPatching/Builtins/FunctionalBuiltins.cs delete mode 100644 src/PatchManager.SassyPatching/Builtins/ListBuiltins.cs delete mode 100644 src/PatchManager.SassyPatching/Builtins/MathBuiltins.cs delete mode 100644 src/PatchManager.SassyPatching/Builtins/MetaBuiltins.cs delete mode 100644 src/PatchManager.SassyPatching/Builtins/ReflectionBuiltins.cs delete mode 100644 src/PatchManager.SassyPatching/Builtins/StringBuiltins.cs delete mode 100644 src/PatchManager.SassyPatching/Builtins/TypeConversion.cs delete mode 100644 src/PatchManager.SassyPatching/Coordinate.cs delete mode 100644 src/PatchManager.SassyPatching/DataValue.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/BinaryExpressionTypeException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/DataValueOperationException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/DictionaryKeyNotFoundException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/FunctionReturnException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/ImportException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/IncorrectTypeException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/InterpolationException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/InterpreterException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/InvalidVariableReferenceException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/InvocationException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/ListIndexOutOfRangeException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/NotModifiableException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/TypeConversionException.cs delete mode 100644 src/PatchManager.SassyPatching/Exceptions/UnaryTypeException.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/BoundPatchFunction.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/Environment.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/GlobalEnvironment.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/ManagedPatchFunction.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/ManagedPatchLibrary.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/PatchArgument.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/PatchFunction.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/PatchLibrary.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/PatchMixin.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/SassyGenerator.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/SassyPatchClosure.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/SassyPatchFunction.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/SassyPatchLibrary.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/SassyTextPatcher.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/SelectableWithEnvironment.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/Stage.cs delete mode 100644 src/PatchManager.SassyPatching/Execution/Universe.cs delete mode 100644 src/PatchManager.SassyPatching/Interfaces/IModifiable.cs delete mode 100644 src/PatchManager.SassyPatching/Interfaces/INewAsset.cs delete mode 100644 src/PatchManager.SassyPatching/Interfaces/IPatcherRuleSet.cs delete mode 100644 src/PatchManager.SassyPatching/Interfaces/ISelectable.cs delete mode 100644 src/PatchManager.SassyPatching/Modifiables/CustomJTokenModifiable.cs delete mode 100644 src/PatchManager.SassyPatching/Modifiables/JTokenModifiable.cs delete mode 100644 src/PatchManager.SassyPatching/NewAssets/NewGenericAsset.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Argument.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Attributes/NewAttribute.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireAnd.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireExpression.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireGuid.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireNot.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireOr.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Attributes/RequireModAttribute.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Attributes/RunAtStageAttribute.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Attributes/SelectorAttribute.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Block.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/CallArgument.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/ErrorNode.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Add.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/And.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Binary.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Divide.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/EqualTo.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/GreaterThan.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/GreaterThanEqual.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/LesserThan.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/LesserThanEqual.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Multiply.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/NotEqualTo.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Or.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Remainder.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Subscript.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Subtract.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Closure.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Expression.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/ListNode.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/LocalVariableReference.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/MemberCall.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/ObjectNode.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/SimpleCall.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Ternary.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Implicit.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitAdd.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitDivide.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitMultiply.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitSubtract.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Negate.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Not.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Positive.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Unary.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/ValueNode.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Expressions/VariableReference.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Indexers/EverythingIndexer.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Indexers/Indexer.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Indexers/SingleIndexer.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/KeyValueNode.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Node.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/SassyPatch.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/ChildSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/ClassCaptureSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/ClassSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/CombinationSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/ElementAdditionSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/ElementSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/EnsureSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/IntersectionSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/NameSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/RulesetSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/Selector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/WildcardSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/WithoutClassSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Selectors/WithoutNameSelector.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/Conditional.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/Each.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/For.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/FunctionLevel/Return.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/SelectionBlock.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/DeleteValue.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/Field.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/ISelectionAction.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MergeValue.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MixinBlockInclude.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MixinInclude.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MixinSlot.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/SetValue.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/ConfigCreation.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/ConfigUpdate.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/Function.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/Import.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/Mixin.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/PatchDeclaration.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/StageDefinition.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/StageDefinitionAttribute.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/VariableDeclaration.cs delete mode 100644 src/PatchManager.SassyPatching/Nodes/Statements/While.cs delete mode 100644 src/PatchManager.SassyPatching/PatchManager.SassyPatching.csproj delete mode 100644 src/PatchManager.SassyPatching/Selectables/JTokenSelectable.cs delete mode 100644 src/PatchManager.SassyPatching/SelectionUtilities.cs delete mode 100644 src/PatchManager.SassyPatching/Transformer.cs delete mode 100644 src/PatchManager.SassyPatching/Utility/Extensions.cs delete mode 100644 src/PatchManager.SassyPatching/Utility/GlobalUsings.cs delete mode 100644 src/PatchManager.Science/Modifiables/DiscoverablesModifiable.cs delete mode 100644 src/PatchManager.Science/Modifiables/ExperimentModifiable.cs delete mode 100644 src/PatchManager.Science/Modifiables/RegionsModifiable.cs delete mode 100644 src/PatchManager.Science/Modifiables/ScienceModifiable.cs delete mode 100644 src/PatchManager.Science/PatchManager.Science.csproj delete mode 100644 src/PatchManager.Science/Rulesets/DiscoverablesRuleset.cs delete mode 100644 src/PatchManager.Science/Rulesets/ExperimentRuleset.cs delete mode 100644 src/PatchManager.Science/Rulesets/RegionsRuleset.cs delete mode 100644 src/PatchManager.Science/Rulesets/ScienceRuleset.cs delete mode 100644 src/PatchManager.Science/ScienceModule.cs delete mode 100644 src/PatchManager.Science/Selectables/DiscoverablesSelectable.cs delete mode 100644 src/PatchManager.Science/Selectables/ExperimentSelectable.cs delete mode 100644 src/PatchManager.Science/Selectables/RegionsSelectable.cs delete mode 100644 src/PatchManager.Science/Selectables/ScienceSelectable.cs delete mode 100644 src/PatchManager.Shared/Extensions.cs delete mode 100644 src/PatchManager.Shared/Interfaces/ITextAssetGenerator.cs delete mode 100644 src/PatchManager.Shared/Interfaces/ITextPatcher.cs delete mode 100644 src/PatchManager.Shared/Logging.cs delete mode 100644 src/PatchManager.Shared/Modules/BaseModule.cs delete mode 100644 src/PatchManager.Shared/Modules/IModule.cs delete mode 100644 src/PatchManager.Shared/Modules/ModuleManager.cs delete mode 100644 src/PatchManager.Shared/PatchManager.Shared.csproj delete mode 100644 src/PatchManager.Shared/Properties/AssemblyInfo.cs delete mode 100644 src/PatchManager/PatchManager.csproj delete mode 100644 src/PatchManager/PatchManagerPlugin.cs diff --git a/.idea/.idea.PatchManager/.idea/.gitignore b/.idea/.idea.PatchManager/.idea/.gitignore new file mode 100644 index 0000000..0b0518c --- /dev/null +++ b/.idea/.idea.PatchManager/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/modules.xml +/.idea.PatchManager.iml +/projectSettingsUpdater.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.PatchManager/.idea/.name b/.idea/.idea.PatchManager/.idea/.name new file mode 100644 index 0000000..aee2c7b --- /dev/null +++ b/.idea/.idea.PatchManager/.idea/.name @@ -0,0 +1 @@ +PatchManager \ No newline at end of file diff --git a/Directory.Build.props.meta b/Directory.Build.props.meta new file mode 100644 index 0000000..168af32 --- /dev/null +++ b/Directory.Build.props.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 69d4349556cb9c44f894973d867a1935 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor.meta b/Editor.meta new file mode 100644 index 0000000..17047e9 --- /dev/null +++ b/Editor.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d0f5c84b3dc645a1bbf53463d2d5b38a +timeCreated: 1739405494 \ No newline at end of file diff --git a/Editor/PatchImporter.cs b/Editor/PatchImporter.cs new file mode 100644 index 0000000..55c1260 --- /dev/null +++ b/Editor/PatchImporter.cs @@ -0,0 +1,17 @@ +using System.IO; +using UnityEditor.AssetImporters; +using UnityEngine; + +namespace PatchManager.Editor +{ + [ScriptedImporter(1, "patch")] + public class PatchImporter: ScriptedImporter + { + public override void OnImportAsset(AssetImportContext ctx) + { + var asset = new TextAsset(File.ReadAllText(ctx.assetPath)); + ctx.AddObjectToAsset(ctx.assetPath, asset); + ctx.SetMainObject(asset); + } + } +} \ No newline at end of file diff --git a/Editor/PatchImporter.cs.meta b/Editor/PatchImporter.cs.meta new file mode 100644 index 0000000..8f3bb99 --- /dev/null +++ b/Editor/PatchImporter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ab83793ff53f4744b6030d17462c7a84 +timeCreated: 1748086433 \ No newline at end of file diff --git a/Editor/Tests.meta b/Editor/Tests.meta new file mode 100644 index 0000000..8cc3998 --- /dev/null +++ b/Editor/Tests.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ea16c937ef7c46b2b671010f6caaf785 +timeCreated: 1739405498 \ No newline at end of file diff --git a/Editor/Tests/ParsingTests.cs b/Editor/Tests/ParsingTests.cs new file mode 100644 index 0000000..a9515f2 --- /dev/null +++ b/Editor/Tests/ParsingTests.cs @@ -0,0 +1,3093 @@ +using System.IO; +using Antlr4.Runtime; +using NUnit.Framework; +using PatchManager.SassyPatching.Nodes; +using PatchManager.SassyPatching.Nodes.Expressions.Binary; +using PatchManager.SassyPatching.Nodes.Expressions.Unary; +using PatchManager.SassyPatching.Tests.Validators; +using PatchManager.SassyPatching.Tests.Validators.Attributes; +using PatchManager.SassyPatching.Tests.Validators.Expressions; +using PatchManager.SassyPatching.Tests.Validators.Selectors; +using PatchManager.SassyPatching.Tests.Validators.Statements; +using PatchManager.SassyPatching.Tests.Validators.Statements.FunctionLevel; +using PatchManager.SassyPatching.Tests.Validators.Statements.SelectionLevel; +using PatchManager.SassyPatching.Tests.Validators.Statements.TopLevel; +using SassyPatchGrammar; + +// ReSharper disable RedundantEmptyObjectOrCollectionInitializer + +namespace PatchManager.SassyPatching.Tests +{ + /// + /// A class containing all of the tests for the parser and the Transformer class + /// + public class ParsingTests + { +#pragma warning disable CS8618 + private Transformer _tokenTransformer; +#pragma warning restore CS8618 + + /// + /// Sets up the parser tests by creating the transformer to be tested + /// + [SetUp] + public void Setup() + { + _tokenTransformer = new Transformer(Assert.Fail); + } + + private class FailErrorListener : IAntlrErrorListener + { + internal static readonly FailErrorListener Instance = new(); + private FailErrorListener() {} + public void SyntaxError(TextWriter output, IRecognizer recognizer, IToken offendingSymbol, int line, int charPositionInLine, + string msg, RecognitionException e) + { + Assert.Fail($"{line}:{charPositionInLine}: {msg}"); + } + } + + private SassyPatch Parse(string testPatch) + { + var charStream = CharStreams.fromString(testPatch); + var lexer = new sassy_lexer(charStream); + var tokenStream = new CommonTokenStream(lexer); + var parser = new sassy_parser(tokenStream); + parser.AddErrorListener(FailErrorListener.Instance); + var patchContext = parser.patch(); + _tokenTransformer.Errored = false; + var patch = _tokenTransformer.Visit(patchContext) as SassyPatch; + Assert.That(_tokenTransformer.Errored, Is.False); + return patch!; + } + + private void Match(string patch, ParseValidator validator) + { + var parsed = Parse(patch); + Assert.That(validator.Validate(parsed), Is.True, "Parse tree does not match the validation criterion"); + } + + #region Top Level Statement Tests + + /// + /// Tests single line comments + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests single line comments")] + public void SingleLineComments() + { + const string patch = + @" +// This is a single line comment +$variable: 5; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }; + + Match(patch, validator); + } + + /// + /// Tests single line comments + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests multi line comments")] + public void MultiLineComment() + { + const string patch = + @" +/* + * This is a multiline comment + */ +$variable: 5; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }; + Match(patch, validator); + } + + /// + /// Tests an import declaration + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an import declaration")] + public void ImportDeclaration() + { + const string patch = @" +@use 'a:b:c'; +"; + var validator = new PatchValidator + { + new ImportValidator + { + Library = "a:b:c" + } + }; + Match(patch, validator); + } + + + /// + /// Tests a top level variable declaration + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a top level variable declaration")] + public void TopLevelVariableDeclaration() + { + const string patch = + @" +$variable: 5; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a function definition w/o any arguments or body + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a function definition w/o any arguments or body")] + public void FunctionDefinitionNoArgumentsNoBody() + { + const string patch = + @" +@function test-function() { +} +"; + var validator = new PatchValidator + { + new FunctionValidator + { + Name = "test-function", + Arguments = new(), + Body = new() + } + }; + Match(patch, validator); + } + + /// + /// Tests a function definition w/ a single argument that has no default value and no body + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a function definition w/ a single argument that has no default value and no body")] + public void FunctionDefinitionSingleArgumentNoDefaultNoBody() + { + const string patch = + @" +@function test-function($arg) { +} +"; + var validator = new PatchValidator + { + new FunctionValidator + { + Name = "test-function", + Arguments = new() + { + new ArgumentValidator + { + Name = "arg" + } + }, + Body = new() + } + }; + Match(patch, validator); + } + + /// + /// Tests a function definition w/ a single argument that has a default value and no body + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a function definition w/ a single argument that has a default value and no body")] + public void FunctionDefinitionSingleArgumentDefaultNoBody() + { + const string patch = + @" +@function test-function($arg: 5) { +} +"; + var validator = new PatchValidator + { + new FunctionValidator + { + Name = "test-function", + Arguments = new() + { + new ArgumentValidator + { + Name = "arg", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }, + Body = new() + } + }; + Match(patch, validator); + } + + /// + /// Tests a function definition w/ a single argument that has a default value and a body that returns that value + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = + "Tests a function definition w/ a single argument that has a default value and a body that returns that value")] + public void FunctionDefinitionSingleArgumentDefaultReturn() + { + const string patch = + @" +@function test-function($arg: 5) { + @return $arg; +} +"; + var validator = new PatchValidator + { + new FunctionValidator + { + Name = "test-function", + Arguments = new() + { + new ArgumentValidator + { + Name = "arg", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }, + Body = new() + { + new ReturnValidator + { + ReturnedValue = new VariableReferenceValidator + { + VariableName = "arg" + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a mixin definition w/o any arguments or body + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a mixin definition w/o any arguments or body")] + public void MixinDefinitionNoArgumentsNoBody() + { + const string patch = + @" +@mixin test-mixin() { +} +"; + var validator = new PatchValidator + { + new MixinValidator + { + Name = "test-mixin", + Arguments = new(), + Body = new() + } + }; + Match(patch, validator); + } + + /// + /// Tests a mixin definition w/ a single argument that has no default value and no body + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a mixin definition w/ a single argument that has no default value and no body")] + public void MixinDefinitionSingleArgumentNoDefaultNoBody() + { + const string patch = + @" +@mixin test-mixin($arg) { +} +"; + var validator = new PatchValidator + { + new MixinValidator + { + Name = "test-mixin", + Arguments = new() + { + new ArgumentValidator + { + Name = "arg" + } + }, + Body = new() + } + }; + Match(patch, validator); + } + + /// + /// Tests a mixin definition w/ a single argument that has a default value and no body + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a mixin definition w/ a single argument that has a default value and no body")] + public void MixinDefinitionSingleArgumentDefaultNoBody() + { + const string patch = + @" +@mixin test-mixin($arg: 5) { +} +"; + var validator = new PatchValidator + { + new MixinValidator + { + Name = "test-mixin", + Arguments = new() + { + new ArgumentValidator + { + Name = "arg", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }, + Body = new() + } + }; + Match(patch, validator); + } + + /// + /// Tests a mixin definition w/ a single argument that has a default value and a body that returns that value + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = + "Tests a mixin definition w/ a single argument that has a default value and a body that returns that value")] + public void MixinDefinitionSingleArgumentDefaultBody() + { + const string patch = + @" +@mixin test-mixin($arg: 5) { + $var: $arg; +} +"; + var validator = new PatchValidator + { + new MixinValidator + { + Name = "test-mixin", + Arguments = new() + { + new ArgumentValidator + { + Name = "arg", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }, + Body = new() + { + new VariableDeclarationValidator() + { + Variable = "var", + Value = new VariableReferenceValidator + { + VariableName = "arg" + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a top level conditional statement w/ no else or else if + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a top level conditional statement w/ no else or else if")] + public void TopLevelConditionalNoElseIfNoElse() + { + const string patch = + @" +@if true { + $variable: 5; +} +"; + var validator = new PatchValidator + { + new ConditionalValidator + { + Condition = new ValueValidator + { + StoredDataValue = true + }, + Body = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a top level conditional statement w/ an else but no else if + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a top level conditional statement w/ an else but no else if")] + public void TopLevelConditionalNoElseIfElse() + { + const string patch = + @" +@if true +{ + $variable: 5; +} +@else +{ + $variable: 6; +} +"; + var validator = new PatchValidator + { + new ConditionalValidator + { + Condition = new ValueValidator + { + StoredDataValue = true + }, + Body = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }, + Else = new BlockValidator + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 6 + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a top level conditional statement w/ an else if but no else + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a top level conditional statement w/ an else if but no else")] + public void TopLevelConditionalElseIfNoElse() + { + const string patch = + @" +@if true +{ + $variable: 5; +} +@else-if false +{ + $variable: 6; +} +"; + var validator = new PatchValidator + { + new ConditionalValidator + { + Condition = new ValueValidator + { + StoredDataValue = true + }, + Body = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }, + Else = new ConditionalValidator + { + Condition = new ValueValidator + { + StoredDataValue = false + }, + Body = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 6 + } + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a top level conditional statement w/ an else if and an else + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a top level conditional statement w/ an else if and an else")] + public void TopLevelConditionalElseIfElse() + { + const string patch = + @" +@if true +{ + $variable: 5; +} +@else-if false +{ + $variable: 6; +} +@else +{ + $variable: 7; +} +"; + var validator = new PatchValidator + { + new ConditionalValidator + { + Condition = new ValueValidator + { + StoredDataValue = true + }, + Body = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }, + Else = new ConditionalValidator + { + Condition = new ValueValidator + { + StoredDataValue = false + }, + Body = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 6 + } + } + }, + Else = new BlockValidator + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 7 + } + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a simple selection block + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a simple selection block")] + public void SelectionBlock() + { + const string patch = + @" +* { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + } + }; + Match(patch, validator); + } + + #endregion + + #region Attribute Tests + + /// + /// Tests a selection block w/ an @stage attribute + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a selection block w/ an @stage attribute")] + public void StageAttribute() + { + const string patch = + @" +@stage 'init' +* { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new() + { + new RunAtStageAttributeValidator() + { + Stage = "init" + } + }, + Selector = new WildcardSelectorValidator(), + Actions = new() + } + }; + Match(patch, validator); + } + + #endregion + + #region Selector Tests + + /// + /// Tests an element selector + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an element selector")] + public void ElementSelector() + { + const string patch = + @" +element { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new ElementSelectorValidator + { + ElementName = "element" + }, + Actions = new(), + } + }; + Match(patch, validator); + } + + /// + /// Tests a class selector + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a class selector")] + public void ClassSelector() + { + const string patch = + @" +.class { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new ClassSelectorValidator + { + ClassName = "class" + }, + Actions = new(), + } + }; + Match(patch, validator); + } + + /// + /// Tests a name selector + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a name selector")] + public void NameSelector() + { + const string patch = + @" +#name { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new NameSelectorValidator + { + NamePattern = "name" + }, + Actions = new(), + } + }; + Match(patch, validator); + } + + /// + /// Tests a ruleset selector + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a ruleset selector")] + public void RulesetSelector() + { + const string patch = + @" +:ruleset { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new RulesetSelectorValidator + { + RulesetName = "ruleset" + }, + Actions = new(), + } + }; + Match(patch, validator); + } + + /// + /// Tests a combination selector + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a combination selector")] + public void CombinationSelector() + { + const string patch = + @" +a, b, c { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new CombinationSelectorValidator + { + new ElementSelectorValidator + { + ElementName = "a" + }, + new ElementSelectorValidator + { + ElementName = "b" + }, + new ElementSelectorValidator + { + ElementName = "c" + } + }, + Actions = new(), + } + }; + Match(patch, validator); + } + + /// + /// Tests a child selector + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a child selector")] + public void ChildSelector() + { + const string patch = + @" +a > .b { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new ChildSelectorValidator + { + Parent = new ElementSelectorValidator + { + ElementName = "a" + }, + Child = new ClassSelectorValidator + { + ClassName = "b" + } + }, + Actions = new(), + } + }; + Match(patch, validator); + } + + /// + /// Tests an intersection selector + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an intersection selector")] + public void IntersectionSelector() + { + const string patch = + @" +a b c { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new IntersectionSelectorValidator + { + new ElementSelectorValidator + { + ElementName = "a" + }, + new ElementSelectorValidator + { + ElementName = "b" + }, + new ElementSelectorValidator + { + ElementName = "c" + } + }, + Actions = new(), + } + }; + Match(patch, validator); + } + + /// + /// Tests a without class selector + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a without class selector")] + public void WithoutClassSelector() + { + const string patch = + @" +~.class { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WithoutClassSelectorValidator + { + ClassName = "class" + }, + Actions = new(), + } + }; + Match(patch, validator); + } + + /// + /// Tests a without name selector + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a without name selector")] + public void WithoutNameSelector() + { + const string patch = + @" +~#name { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WithoutNameSelectorValidator + { + NamePattern = "name" + }, + Actions = new(), + } + }; + Match(patch, validator); + } + + /// + /// Tests a wildcard selector + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a wildcard selector")] + public void WildcardSelector() + { + const string patch = + @" +* { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + } + }; + Match(patch, validator); + } + + /// + /// Tests a complex child selector + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a complex child selector")] + public void ComplexChildSelector() + { + const string patch = + @" +:parts * > ResourceContainers > * { + // Empty +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new ChildSelectorValidator + { + Parent = new ChildSelectorValidator + { + Parent = new IntersectionSelectorValidator + { + new RulesetSelectorValidator + { + RulesetName = "parts" + }, + new WildcardSelectorValidator() + }, + Child = new ElementSelectorValidator + { + ElementName = "ResourceContainers" + } + }, + Child = new WildcardSelectorValidator() + }, + Actions = new(), + } + }; + Match(patch, validator); + } + + #endregion + + #region Selection Action Tests + + /// + /// Tests a selection level variable declaration + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a selection level variable declaration")] + public void SelectionLevelVariableDeclaration() + { + const string patch = + @" +* { + $variable: 5; +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a selection level conditional statement w/ no else or else if + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a selection level conditional statement w/ no else or else if")] + public void SelectionLevelConditionalNoElseIfNoElse() + { + const string patch = + @" +* { + @if true { + $variable: 5; + } +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + { + new ConditionalValidator + { + Condition = new ValueValidator + { + StoredDataValue = true + }, + Body = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a selection level conditional statement w/ an else but no else if + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a selection level conditional statement w/ an else but no else if")] + public void SelectionLevelConditionalNoElseIfElse() + { + const string patch = + @" +* { + @if true + { + $variable: 5; + } + @else + { + $variable: 6; + } +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + { + new ConditionalValidator + { + Condition = new ValueValidator + { + StoredDataValue = true + }, + Body = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }, + Else = new BlockValidator + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 6 + } + } + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a selection level conditional statement w/ an else if but no else + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a selection level conditional statement w/ an else if but no else")] + public void SelectionLevelConditionalElseIfNoElse() + { + const string patch = + @" +* { + @if true + { + $variable: 5; + } + @else-if false + { + $variable: 6; + } +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + { + new ConditionalValidator + { + Condition = new ValueValidator + { + StoredDataValue = true + }, + Body = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }, + Else = new ConditionalValidator + { + Condition = new ValueValidator + { + StoredDataValue = false + }, + Body = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 6 + } + } + } + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a selection level conditional statement w/ an else if and an else + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a selection level conditional statement w/ an else if and an else")] + public void SelectionLevelConditionalElseIfElse() + { + const string patch = + @" +* { + @if true + { + $variable: 5; + } + @else-if false + { + $variable: 6; + } + @else + { + $variable: 7; + } +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + { + new ConditionalValidator + { + Condition = new ValueValidator + { + StoredDataValue = true + }, + Body = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 5 + } + } + }, + Else = new ConditionalValidator + { + Condition = new ValueValidator + { + StoredDataValue = false + }, + Body = new() + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 6 + } + } + }, + Else = new BlockValidator + { + new VariableDeclarationValidator + { + Variable = "variable", + Value = new ValueValidator + { + StoredDataValue = 7 + } + } + } + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a set value selection action + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a set value selection action")] + public void SetValueAction() + { + const string patch = + @" +// Note, don't ever run this unless you want to not have a game +* { + @set {}; +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + { + new SetValueValidator + { + Value = new ObjectValidator + { + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a deletion selection action + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a deletion selection action")] + public void DeletionAction() + { + const string patch = + @" +// Note, don't ever run this unless you want to not have a game +* { + @delete; +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + { + new DeleteValueValidator() + } + } + }; + Match(patch,validator); + } + + /// + /// Tests a merge selection action + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a merge selection action")] + public void MergeAction() + { + const string patch = + @" +* { + @merge {}; +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + { + new MergeValueValidator + { + Value = new ObjectValidator + { + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a field set selection action w/ an element key and no indexer + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a field set selection action w/ an element key and no indexer")] + public void FieldSetElementKeyNoIndexer() + { + const string patch = + @" +* { + x: 5; +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + { + new FieldValidator + { + FieldName = "x", + FieldValue = new ValueValidator + { + StoredDataValue = 5 + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a field set selection action w/ a string key and no indexer + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a field set selection action w/ a string key and no indexer")] + public void FieldSetStringKeyNoIndexer() + { + const string patch = + @" +* { + 'x': 5; +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + { + new FieldValidator + { + FieldName = "x", + FieldValue = new ValueValidator + { + StoredDataValue = 5 + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a field set selection action w/ an element key and a number indexer + /// +// [Test(TestOf = typeof(Transformer), Author = "Cheese", +// Description = "Tests a field set selection action w/ an element key and a number indexer")] +// public void FieldSetElementKeyNumberIndexer() +// { +// const string patch = +// @" +// * { +// x[0]: 5; +// } +// "; +// var validator = new PatchValidator +// { +// new SelectionBlockValidator +// { +// Attributes = new(), +// Selector = new WildcardSelectorValidator(), +// Actions = new() +// { +// new FieldValidator +// { +// FieldName = "x", +// Indexer = new NumberIndexerValidator +// { +// Index = 0 +// }, +// FieldValue = new ValueValidator +// { +// StoredDataValue = 5 +// } +// } +// } +// } +// }; +// Match(patch, validator); +// } + + /// + /// Tests a field set selection action w/ a string key and a number indexer + /// +// [Test(TestOf = typeof(Transformer), Author = "Cheese", +// Description = "Tests a field set selection action w/ a string key and a number indexer")] +// public void FieldSetStringKeyNumberIndexer() +// { +// const string patch = +// @" +// * { +// 'x'[0]: 5; +// } +// "; +// var validator = new PatchValidator +// { +// new SelectionBlockValidator +// { +// Attributes = new(), +// Selector = new WildcardSelectorValidator(), +// Actions = new() +// { +// new FieldValidator +// { +// FieldName = "x", +// Indexer = new NumberIndexerValidator +// { +// Index = 0 +// }, +// FieldValue = new ValueValidator +// { +// StoredDataValue = 5 +// } +// } +// } +// } +// }; +// Match(patch, validator); +// } + + /// + /// Tests a field set selection action w/ an element key and an element indexer + /// +// [Test(TestOf = typeof(Transformer), Author = "Cheese", +// Description = "Tests a field set selection action w/ an element key and an element indexer")] +// public void FieldSetElementKeyElementIndexer() +// { +// const string patch = +// @" +// * { +// x[y]: 5; +// } +// "; +// var validator = new PatchValidator +// { +// new SelectionBlockValidator +// { +// Attributes = new(), +// Selector = new WildcardSelectorValidator(), +// Actions = new() +// { +// new FieldValidator +// { +// FieldName = "x", +// Indexer = new ElementIndexerValidator +// { +// ElementName = "y" +// }, +// FieldValue = new ValueValidator +// { +// StoredDataValue = 5 +// } +// } +// } +// } +// }; +// Match(patch, validator); +// } + + /// + /// Tests a field set selection action w/ a string key and an element indexer + /// +// [Test(TestOf = typeof(Transformer), Author = "Cheese", +// Description = "Tests a field set selection action w/ a string key and an element indexer")] +// public void FieldSetStringKeyElementIndexer() +// { +// const string patch = +// @" +// * { +// 'x'[y]: 5; +// } +// "; +// var validator = new PatchValidator +// { +// new SelectionBlockValidator +// { +// Attributes = new(), +// Selector = new WildcardSelectorValidator(), +// Actions = new() +// { +// new FieldValidator +// { +// FieldName = "x", +// Indexer = new ElementIndexerValidator +// { +// ElementName = "y" +// }, +// FieldValue = new ValueValidator +// { +// StoredDataValue = 5 +// } +// } +// } +// } +// }; +// Match(patch, validator); +// } + + /// + /// Tests a field set selection action w/ an element key and a class indexer + /// +// [Test(TestOf = typeof(Transformer), Author = "Cheese", +// Description = "Tests a field set selection action w/ an element key and a class indexer")] +// public void FieldSetElementKeyClassIndexer() +// { +// const string patch = +// @" +// * { +// x[.y]: 5; +// } +// "; +// var validator = new PatchValidator +// { +// new SelectionBlockValidator +// { +// Attributes = new(), +// Selector = new WildcardSelectorValidator(), +// Actions = new() +// { +// new FieldValidator +// { +// FieldName = "x", +// Indexer = new ClassIndexerValidator +// { +// ClassName = "y" +// }, +// FieldValue = new ValueValidator +// { +// StoredDataValue = 5 +// } +// } +// } +// } +// }; +// Match(patch, validator); +// } + + /// + /// Tests a field set selection action w/ a string key and a class indexer + /// +// [Test(TestOf = typeof(Transformer), Author = "Cheese", +// Description = "Tests a field set selection action w/ a string key and a class indexer")] +// public void FieldSetStringKeyClassIndexer() +// { +// const string patch = +// @" +// * { +// 'x'[.y]: 5; +// } +// "; +// var validator = new PatchValidator +// { +// new SelectionBlockValidator +// { +// Attributes = new(), +// Selector = new WildcardSelectorValidator(), +// Actions = new() +// { +// new FieldValidator +// { +// FieldName = "x", +// Indexer = new ClassIndexerValidator +// { +// ClassName = "y" +// }, +// FieldValue = new ValueValidator +// { +// StoredDataValue = 5 +// } +// } +// } +// } +// }; +// Match(patch,validator); +// } + + /// + /// Tests a field set selection action w/ an element key and a string indexer + /// +// [Test(TestOf = typeof(Transformer), Author = "Cheese", +// Description = "Tests a field set selection action w/ an element key and a string indexer")] +// public void FieldSetElementKeyStringIndexer() +// { +// const string patch = +// @" +// * { +// x['y']: 5; +// } +// "; +// var validator = new PatchValidator +// { +// new SelectionBlockValidator +// { +// Attributes = new(), +// Selector = new WildcardSelectorValidator(), +// Actions = new() +// { +// new FieldValidator +// { +// FieldName = "x", +// Indexer = new StringIndexerValidator +// { +// Index = "y" +// }, +// FieldValue = new ValueValidator +// { +// StoredDataValue = 5 +// } +// } +// } +// } +// }; +// Match(patch, validator); +// } + + /// + /// Tests a field set selection action w/ a string key and a string indexer + /// +// [Test(TestOf = typeof(Transformer), Author = "Cheese", +// Description = "Tests a field set selection action w/ a string key and a string indexer")] +// public void FieldSetStringKeyStringIndexer() +// { +// const string patch = +// @" +// * { +// 'x'['y']: 5; +// } +// "; +// var validator = new PatchValidator +// { +// new SelectionBlockValidator +// { +// Attributes = new(), +// Selector = new WildcardSelectorValidator(), +// Actions = new() +// { +// new FieldValidator +// { +// FieldName = "x", +// Indexer = new StringIndexerValidator +// { +// Index = "y" +// }, +// FieldValue = new ValueValidator +// { +// StoredDataValue = 5 +// } +// } +// } +// } +// }; +// Match(patch, validator); +// } + + /// + /// Tests a nested selection block as a selection action + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a nested selection block as a selection action")] + public void NestedSelectionBlock() + { + const string patch = + @" +* { + * { + } +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a mixin include as a selection action + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a mixin include as a selection action")] + public void MixinInclude() + { + const string patch = + @" +* { + @include test-mixin() +} +"; + var validator = new PatchValidator + { + new SelectionBlockValidator + { + Attributes = new(), + Selector = new WildcardSelectorValidator(), + Actions = new() + { + new MixinIncludeValidator + { + MixinName = "test-mixin", + Arguments = new() + } + } + } + }; + Match(patch, validator); + } + + #endregion + + #region Expression Tests + + /// + /// Tests an implicit addition expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an implicit addition expression")] + public void ImplicitAddition() + { + const string patch = + @" +$x +: 2; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new UnaryValidator + { + Child = new ValueValidator + { + StoredDataValue = 2 + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests an implicit subtraction expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an implicit subtraction expression")] + public void ImplicitSubtraction() + { + const string patch = + @" +$x -: 2; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new UnaryValidator + { + Child = new ValueValidator + { + StoredDataValue = 2 + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests an implicit multiplication expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an implicit multiplication expression")] + public void ImplicitMultiplication() + { + const string patch = + @" +$x *: 2; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new UnaryValidator + { + Child = new ValueValidator + { + StoredDataValue = 2 + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests an implicit division expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an implicit division expression")] + public void ImplicitDivision() + { + const string patch = + @" +$x /: 2; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new UnaryValidator + { + Child = new ValueValidator + { + StoredDataValue = 2 + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a variable reference expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a variable reference expression")] + public void VariableReference() + { + const string patch = + @" +$x: $y; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new VariableReferenceValidator + { + VariableName = "y" + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a negation expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a negation expression")] + public void Negate() + { + const string patch = + @" +$x: (-2); +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new UnaryValidator + { + Child = new ValueValidator + { + StoredDataValue = 2 + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a positive expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a positive expression")] + public void Positive() + { + const string patch = + @" +$x: (+2); +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new UnaryValidator + { + Child = new ValueValidator + { + StoredDataValue = 2 + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests an inversion expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an inversion expression")] + public void Inversion() + { + const string patch = + @" +$x: not false; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new UnaryValidator + { + Child = new ValueValidator + { + StoredDataValue = false + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a function call w/ no unnamed or named arguments + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a function call w/ no unnamed or named arguments")] + public void CallNoUnnamedNoNamed() + { + const string patch = + @" +$x: test-function(); +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new SimpleCallValidator + { + FunctionName = "test-function", + Arguments = new() + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a function call w/ an unnamed argument but no named arguments + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a function call w/ an unnamed argument but no named arguments")] + public void CallUnnamedNoNamed() + { + const string patch = + @" +$x: test-function(5); +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new SimpleCallValidator + { + FunctionName = "test-function", + Arguments = new() + { + new CallArgumentValidator + { + ArgumentValue = new ValueValidator + { + StoredDataValue = 5 + } + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a function call w/ a named argument but no unnamed arguments + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a function call w/ a named argument but no unnamed arguments")] + public void CallNoUnnamedNamed() + { + const string patch = + @" +$x: test-function($a: 5); +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new SimpleCallValidator + { + FunctionName = "test-function", + Arguments = new() + { + new CallArgumentValidator + { + ArgumentName = "a", + ArgumentValue = new ValueValidator + { + StoredDataValue = 5 + } + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a function call w/ a named argument and an unnamed argument + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests a function call w/ a named argument and an unnamed argument")] + public void CallUnnamedNamed() + { + const string patch = + @" +$x: test-function(6, $a: 5); +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new SimpleCallValidator + { + FunctionName = "test-function", + Arguments = new() + { + new CallArgumentValidator + { + ArgumentValue = new ValueValidator + { + StoredDataValue = 6 + } + }, + new CallArgumentValidator + { + ArgumentName = "a", + ArgumentValue = new ValueValidator + { + StoredDataValue = 5 + } + } + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a member call w/o any arguments + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a member call w/o any arguments")] + public void MemberCall() + { + const string patch = + @" +$x: $y:method(); +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new MemberCallValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + FunctionName = "method", + Arguments = new() + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a subscript expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a subscript expression")] + public void Subscript() + { + const string patch = + @" +$x: $y[$z]; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a multiplication expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a multiplication expression")] + public void Multiply() + { + const string patch = + @" +$x: $y * $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a division expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a division expression")] + public void Divide() + { + const string patch = + @" +$x: $y / $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a remainder expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a remainder expression")] + public void Remainder() + { + const string patch = + @" +$x: $y % $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests an addition expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an addition expression")] + public void Add() + { + const string patch = + @" +$x: $y + $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a subtraction expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a subtraction expression")] + public void Subtract() + { + const string patch = + @" +$x: $y - $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a greater than expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a greater than expression")] + public void GreaterThan() + { + const string patch = + @" +$x: $y > $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a lesser than expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a lesser than expression")] + public void LesserThan() + { + const string patch = + @" +$x: $y < $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a greater than equal expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a greater than equal expression")] + public void GreaterThanEqual() + { + const string patch = + @" +$x: $y >= $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a lesser than equal expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a lesser than equal expression")] + public void LesserThanEqual() + { + const string patch = + @" +$x: $y <= $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests an equal to expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an equal to expression")] + public void EqualTo() + { + const string patch = + @" +$x: $y == $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a not equal to expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a not equal to expression")] + public void NotEqualTo() + { + const string patch = + @" +$x: $y != $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests an and expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an and expression")] + public void And() + { + const string patch = + @" +$x: $y and $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests an or expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an or expression")] + public void Or() + { + const string patch = + @" +$x: $y or $z; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a ternary expression + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a ternary expression")] + public void Ternary() + { + const string patch = + @" +$x: $y if $z else $w; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new TernaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + Condition = new VariableReferenceValidator + { + VariableName = "z" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "w" + } + } + } + }; + Match(patch, validator); + } + + #endregion + + #region Operator Precedence Tests + + /// + /// Tests that multiplication has a higher precedence than addition + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests that multiplication has a higher precedence than addition")] + public void MultiplicativePrecedence() + { + const string patch = + @" +$x: $y * $z + $w * $v; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + }, + RightHandSide = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "w" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "v" + } + }, + } + } + }; + Match(patch, validator); + } + + /// + /// Tests that subscription has a higher precedence than addition + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", + Description = "Tests that subscription has a higher precedence than addition")] + public void SubscriptionPrecedence() + { + const string patch = + @" +$x: $y * $z + $w[$v]; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new BinaryValidator + { + LeftHandSide = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "y" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "z" + } + }, + RightHandSide = new BinaryValidator + { + LeftHandSide = new VariableReferenceValidator + { + VariableName = "w" + }, + RightHandSide = new VariableReferenceValidator + { + VariableName = "v" + } + }, + } + } + }; + Match(patch, validator); + } + + #endregion + + #region Value Tests + + /// + /// Tests a deletion value + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a deletion value")] + public void DeleteValue() + { + const string patch = + @" +$x: @delete; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new ValueValidator + { + StoredDataValue = new DataValue(DataValue.DataType.Deletion) + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a true value + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a true value")] + public void True() + { + const string patch = + @" +$x: true; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new ValueValidator + { + StoredDataValue = true + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a false value + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a false value")] + public void False() + { + const string patch = + @" +$x: false; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new ValueValidator + { + StoredDataValue = false + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a number value + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a number value")] + public void Number() + { + const string patch = + @" +$x: 6.75; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new ValueValidator + { + StoredDataValue = 6.75 + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a string value + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a string value")] + public void String() + { + const string patch = + @" +$x: 'a\nb\n'; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new ValueValidator + { + StoredDataValue = "a\nb\n" + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a null value + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a null value")] + public void None() + { + const string patch = + @" +$x: null; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new ValueValidator + { + StoredDataValue = new DataValue(DataValue.DataType.None) + } + } + }; + Match(patch, validator); + } + + /// + /// Tests a list value + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a list value")] + public void List() + { + const string patch = + @" +$x: [1,'2',true,4,null]; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new ListValidator + { + new ValueValidator + { + StoredDataValue = 1 + }, + new ValueValidator + { + StoredDataValue = "2" + }, + new ValueValidator + { + StoredDataValue = true + }, + new ValueValidator + { + StoredDataValue = 4 + }, + new ValueValidator + { + StoredDataValue = new DataValue(DataValue.DataType.None) + } + } + } + }; + Match(patch, validator); + } + + /// + /// Tests an object value + /// + [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an object value")] + public void Object() + { + const string patch = + @" +$x: { + a: 1, + 'b': 2, +}; +"; + var validator = new PatchValidator + { + new VariableDeclarationValidator + { + Variable = "x", + Value = new ObjectValidator + { + new KeyValueValidator + { + Key = "a", + Value = new ValueValidator + { + StoredDataValue = 1 + } + }, + new KeyValueValidator + { + Key = "b", + Value = new ValueValidator + { + StoredDataValue = 2 + } + } + } + } + }; + Match(patch, validator); + } + + #endregion + } +} \ No newline at end of file diff --git a/Editor/Tests/ParsingTests.cs.meta b/Editor/Tests/ParsingTests.cs.meta new file mode 100644 index 0000000..397c0a8 --- /dev/null +++ b/Editor/Tests/ParsingTests.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ef04589ddc496f74e98157b508b47759 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators.meta b/Editor/Tests/Validators.meta new file mode 100644 index 0000000..454ce30 --- /dev/null +++ b/Editor/Tests/Validators.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 395fc4d1321c234428c1935130267bfe +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/ArgumentValidator.cs b/Editor/Tests/Validators/ArgumentValidator.cs new file mode 100644 index 0000000..32adaff --- /dev/null +++ b/Editor/Tests/Validators/ArgumentValidator.cs @@ -0,0 +1,34 @@ +using PatchManager.SassyPatching.Nodes; + +namespace PatchManager.SassyPatching.Tests.Validators +{ + /// + /// Describes a validator for matching nodes of type + /// + public class ArgumentValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string Name = ""; + + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator Value = null; + + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(Argument node) + { + if (Name != node.Name) return false; + if (Value == null && node.Value != null) return false; + if (Value != null && node.Value == null) return false; + if (Value == null && node.Value == null) return true; + return Value!.Validate(node.Value!); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/ArgumentValidator.cs.meta b/Editor/Tests/Validators/ArgumentValidator.cs.meta new file mode 100644 index 0000000..0e0dfc4 --- /dev/null +++ b/Editor/Tests/Validators/ArgumentValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2747e54199e615a448389485fc981f8e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Attributes.meta b/Editor/Tests/Validators/Attributes.meta new file mode 100644 index 0000000..d39a28a --- /dev/null +++ b/Editor/Tests/Validators/Attributes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0fe99ab8eea44fa4d86bde7fdd77b6cc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Attributes/RunAtStageAttributeValidator.cs b/Editor/Tests/Validators/Attributes/RunAtStageAttributeValidator.cs new file mode 100644 index 0000000..c230f39 --- /dev/null +++ b/Editor/Tests/Validators/Attributes/RunAtStageAttributeValidator.cs @@ -0,0 +1,21 @@ +using PatchManager.SassyPatching.Nodes.Attributes; + +namespace PatchManager.SassyPatching.Tests.Validators.Attributes +{ + /// + /// Describes a validator for matching nodes of type + /// + public class RunAtStageAttributeValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string Stage = ""; + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(RunAtStageAttribute node) => node.Stage == Stage; + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Attributes/RunAtStageAttributeValidator.cs.meta b/Editor/Tests/Validators/Attributes/RunAtStageAttributeValidator.cs.meta new file mode 100644 index 0000000..10a6470 --- /dev/null +++ b/Editor/Tests/Validators/Attributes/RunAtStageAttributeValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 873b1d9136fbbbd448973ed0aa4a4129 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/BlockValidator.cs b/Editor/Tests/Validators/BlockValidator.cs new file mode 100644 index 0000000..336608c --- /dev/null +++ b/Editor/Tests/Validators/BlockValidator.cs @@ -0,0 +1,47 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes; + +namespace PatchManager.SassyPatching.Tests.Validators +{ + /// + /// Describes a validator for matching nodes of type + /// + public class BlockValidator : ParseValidator, IEnumerable + { + private readonly List _validators = new(); + + /// + /// Gets an enumerator that enumerates over the validators contained in this validator + /// + /// The enumerator that enumerates over the validators contained in this validator + public IEnumerator GetEnumerator() + { + return _validators.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(Block node) + { + if (node.Children.Count != _validators.Count) return false; + return !_validators.Where((t, i) => !t.Validate(node.Children[i])).Any(); + } + /// + /// Adds a validator to the children of the tree that this validator describes + /// + /// The child validator that should be added to the end as a child of this validator + public void Add(ParseValidator parseValidator) + { + _validators.Add(parseValidator); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/BlockValidator.cs.meta b/Editor/Tests/Validators/BlockValidator.cs.meta new file mode 100644 index 0000000..d078f6c --- /dev/null +++ b/Editor/Tests/Validators/BlockValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e4493cdd5b28b744892bba728dc4c61 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/CallArgumentValidator.cs b/Editor/Tests/Validators/CallArgumentValidator.cs new file mode 100644 index 0000000..8d91741 --- /dev/null +++ b/Editor/Tests/Validators/CallArgumentValidator.cs @@ -0,0 +1,29 @@ +using PatchManager.SassyPatching.Nodes; + +namespace PatchManager.SassyPatching.Tests.Validators +{ + /// + /// Describes a validator for matching nodes of type + /// + public class CallArgumentValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string ArgumentName = null; + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator ArgumentValue = new FalseValidator(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(CallArgument node) + { + if (ArgumentName != node.ArgumentName) return false; + return ArgumentValue.Validate(node.ArgumentValue); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/CallArgumentValidator.cs.meta b/Editor/Tests/Validators/CallArgumentValidator.cs.meta new file mode 100644 index 0000000..3132a9c --- /dev/null +++ b/Editor/Tests/Validators/CallArgumentValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0f53bd19021515e4f95e41663b441158 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Expressions.meta b/Editor/Tests/Validators/Expressions.meta new file mode 100644 index 0000000..bad636b --- /dev/null +++ b/Editor/Tests/Validators/Expressions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3af25d119c0ab454488fbd908a21c117 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Expressions/BinaryValidator.cs b/Editor/Tests/Validators/Expressions/BinaryValidator.cs new file mode 100644 index 0000000..8c36d51 --- /dev/null +++ b/Editor/Tests/Validators/Expressions/BinaryValidator.cs @@ -0,0 +1,27 @@ +using PatchManager.SassyPatching.Nodes.Expressions.Binary; + +namespace PatchManager.SassyPatching.Tests.Validators.Expressions +{ + /// + /// Describes a validator for matching nodes with a type derived from + /// + /// The unary node type that this validator will match + public class BinaryValidator : ParseValidator where T : Binary + { + /// + /// A validator that is used to match against the corresponding node in a node with a type derived from + /// + public ParseValidator LeftHandSide = new FalseValidator(); + /// + /// A validator that is used to match against the corresponding node in a node with a type derived from + /// + public ParseValidator RightHandSide = new FalseValidator(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(T node) => + LeftHandSide.Validate(node.LeftHandSide) && RightHandSide.Validate(node.RightHandSide); + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Expressions/BinaryValidator.cs.meta b/Editor/Tests/Validators/Expressions/BinaryValidator.cs.meta new file mode 100644 index 0000000..fbdce49 --- /dev/null +++ b/Editor/Tests/Validators/Expressions/BinaryValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1bf5305b3a774de488a08a75465c02af +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Expressions/ListValidator.cs b/Editor/Tests/Validators/Expressions/ListValidator.cs new file mode 100644 index 0000000..1363311 --- /dev/null +++ b/Editor/Tests/Validators/Expressions/ListValidator.cs @@ -0,0 +1,48 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes.Expressions; + +namespace PatchManager.SassyPatching.Tests.Validators.Expressions +{ + /// + /// Describes a validator for matching nodes of type + /// + public class ListValidator : ParseValidator, IEnumerable + { + private readonly List _expressions = new(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(ListNode node) + { + if (node.Expressions.Count != _expressions.Count) return false; + return !_expressions.Where((x, y) => !x.Validate(node.Expressions[y])).Any(); + } + + /// + /// Gets an enumerator that enumerates over the validators contained in this validator + /// + /// The enumerator that enumerates over the validators contained in this validator + public IEnumerator GetEnumerator() + { + return _expressions.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Adds a validator to the children of the tree that this validator describes + /// + /// The child validator that should be added to the end as a child of this validator + public void Add(ParseValidator validator) + { + _expressions.Add(validator); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Expressions/ListValidator.cs.meta b/Editor/Tests/Validators/Expressions/ListValidator.cs.meta new file mode 100644 index 0000000..e4035cf --- /dev/null +++ b/Editor/Tests/Validators/Expressions/ListValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f9c424a2bd3b1e34ba939b2d3ca50579 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Expressions/MemberCallValidator.cs b/Editor/Tests/Validators/Expressions/MemberCallValidator.cs new file mode 100644 index 0000000..105052b --- /dev/null +++ b/Editor/Tests/Validators/Expressions/MemberCallValidator.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes.Expressions; + +namespace PatchManager.SassyPatching.Tests.Validators.Expressions +{ + /// + /// Describes a validator for matching nodes of type + /// + public class MemberCallValidator : ParseValidator + { /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator LeftHandSide = new FalseValidator(); + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string FunctionName = ""; + /// + /// A list of validators used to match against the corresponding list of nodes in a value of type + /// + public List Arguments = new(); + + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(MemberCall node) + { + if (!LeftHandSide.Validate(node.LeftHandSide)) return false; + if (node.FunctionName != FunctionName) return false; + if (Arguments.Count != node.Arguments.Count) return false; + return !Arguments.Where((x, y) => !x.Validate(node.Arguments[y])).Any(); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Expressions/MemberCallValidator.cs.meta b/Editor/Tests/Validators/Expressions/MemberCallValidator.cs.meta new file mode 100644 index 0000000..1b9ac7d --- /dev/null +++ b/Editor/Tests/Validators/Expressions/MemberCallValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a774cc3df9e64f047b5cb157d6e5978c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Expressions/ObjectValidator.cs b/Editor/Tests/Validators/Expressions/ObjectValidator.cs new file mode 100644 index 0000000..cf79f0d --- /dev/null +++ b/Editor/Tests/Validators/Expressions/ObjectValidator.cs @@ -0,0 +1,48 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes.Expressions; + +namespace PatchManager.SassyPatching.Tests.Validators.Expressions +{ + /// + /// Describes a validator for matching nodes of type + /// + public class ObjectValidator : ParseValidator, IEnumerable + { + private readonly List _initializers = new(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(ObjectNode node) + { + if (node.Initializers.Count != _initializers.Count) return false; + return !_initializers.Where((x, y) => !x.Validate(node.Initializers[y])).Any(); + } + + /// + /// Gets an enumerator that enumerates over the validators contained in this validator + /// + /// The enumerator that enumerates over the validators contained in this validator + public IEnumerator GetEnumerator() + { + return _initializers.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Adds a validator to the children of the tree that this validator describes + /// + /// The child validator that should be added to the end as a child of this validator + public void Add(KeyValueValidator initializer) + { + _initializers.Add(initializer); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Expressions/ObjectValidator.cs.meta b/Editor/Tests/Validators/Expressions/ObjectValidator.cs.meta new file mode 100644 index 0000000..087eafe --- /dev/null +++ b/Editor/Tests/Validators/Expressions/ObjectValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4e915138f2d442b4a94357849052aa90 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Expressions/SimpleCallValidator.cs b/Editor/Tests/Validators/Expressions/SimpleCallValidator.cs new file mode 100644 index 0000000..a94426c --- /dev/null +++ b/Editor/Tests/Validators/Expressions/SimpleCallValidator.cs @@ -0,0 +1,33 @@ +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes.Expressions; + +namespace PatchManager.SassyPatching.Tests.Validators.Expressions +{ + /// + /// Describes a validator for matching nodes of type + /// + public class SimpleCallValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string FunctionName = ""; + /// + /// A list of validators used to match against the corresponding list of nodes in a value of type + /// + public List Arguments = new(); + + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(SimpleCall node) + { + if (node.FunctionName != FunctionName) return false; + if (Arguments.Count != node.Arguments.Count) return false; + return !Arguments.Where((x, y) => !x.Validate(node.Arguments[y])).Any(); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Expressions/SimpleCallValidator.cs.meta b/Editor/Tests/Validators/Expressions/SimpleCallValidator.cs.meta new file mode 100644 index 0000000..08e0e45 --- /dev/null +++ b/Editor/Tests/Validators/Expressions/SimpleCallValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b2f66851df2ed3d4b8d9feb2df82909f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Expressions/TernaryValidator.cs b/Editor/Tests/Validators/Expressions/TernaryValidator.cs new file mode 100644 index 0000000..fa1eafa --- /dev/null +++ b/Editor/Tests/Validators/Expressions/TernaryValidator.cs @@ -0,0 +1,32 @@ +using PatchManager.SassyPatching.Nodes.Expressions; + +namespace PatchManager.SassyPatching.Tests.Validators.Expressions +{ + /// + /// Describes a validator for matching nodes of type + /// + public class TernaryValidator : ParseValidator + { + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator LeftHandSide = new FalseValidator(); + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator Condition = new FalseValidator(); + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator RightHandSide = new FalseValidator(); + + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(Ternary node) => LeftHandSide.Validate(node.LeftHandSide) && + Condition.Validate(node.Condition) && + RightHandSide.Validate(node.RightHandSide); + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Expressions/TernaryValidator.cs.meta b/Editor/Tests/Validators/Expressions/TernaryValidator.cs.meta new file mode 100644 index 0000000..1ff2d41 --- /dev/null +++ b/Editor/Tests/Validators/Expressions/TernaryValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 81621dd9f4402e54c8ef0870325f6b20 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Expressions/UnaryValidator.cs b/Editor/Tests/Validators/Expressions/UnaryValidator.cs new file mode 100644 index 0000000..0d474fd --- /dev/null +++ b/Editor/Tests/Validators/Expressions/UnaryValidator.cs @@ -0,0 +1,22 @@ +using PatchManager.SassyPatching.Nodes.Expressions.Unary; + +namespace PatchManager.SassyPatching.Tests.Validators.Expressions +{ + /// + /// Describes a validator for matching nodes with a type derived from + /// + /// The unary node type that this validator will match + public class UnaryValidator : ParseValidator where T : Unary + { + /// + /// A validator that is used to match against the corresponding node in a node with a type derived from + /// + public ParseValidator Child = new FalseValidator(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(T node) => Child.Validate(node.Child); + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Expressions/UnaryValidator.cs.meta b/Editor/Tests/Validators/Expressions/UnaryValidator.cs.meta new file mode 100644 index 0000000..4ffc07b --- /dev/null +++ b/Editor/Tests/Validators/Expressions/UnaryValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9017d82d5c900784ea97c6c998c7fb95 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Expressions/ValueValidator.cs b/Editor/Tests/Validators/Expressions/ValueValidator.cs new file mode 100644 index 0000000..508b861 --- /dev/null +++ b/Editor/Tests/Validators/Expressions/ValueValidator.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes.Expressions; + +namespace PatchManager.SassyPatching.Tests.Validators.Expressions +{ + /// + /// Describes a validator for matching nodes of type + /// + public class ValueValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public DataValue StoredDataValue = new DataValue(DataValue.DataType.None); + + private static bool ListCompare(List leftHandSide, List rightHandSide) + { + if (leftHandSide.Count != rightHandSide.Count) + { + return false; + } + return !leftHandSide.Where((t, index) => !GetResult(t, rightHandSide[index])).Any(); + } + + private static bool DictionaryCompare(Dictionary leftHandSide, Dictionary rightHandSide) + { + if (leftHandSide.Count != rightHandSide.Count) + { + return false; + } + + foreach (var kv in leftHandSide) + { + if (rightHandSide.TryGetValue(kv.Key, out var rvalue)) + { + if (!GetResult(kv.Value, rvalue)) + { + return false; + } + } + else + { + return false; + } + } + return true; + } + + private static bool GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + if (leftHandSide.Type != rightHandSide.Type) return false; + + if (leftHandSide.IsBoolean) + { + return leftHandSide.Boolean == rightHandSide.Boolean; + } + + if (leftHandSide.IsReal) + { + // ReSharper disable once CompareOfFloatsByEqualityOperator + return leftHandSide.Real == rightHandSide.Real; + } + + if (leftHandSide.IsInteger) + { + return leftHandSide.Integer == rightHandSide.Integer; + } + + if (leftHandSide.IsString) + { + return leftHandSide.String == rightHandSide.String; + } + + if (leftHandSide.IsList) + { + return ListCompare(leftHandSide.List,rightHandSide.List); + } + + if (leftHandSide.IsDictionary) + { + return DictionaryCompare(leftHandSide.Dictionary, rightHandSide.Dictionary); + } + + return true; + } + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(ValueNode node) + { + // Now we compare equality between values + // Good thing is there should only be a few value types + return GetResult(StoredDataValue, node.StoredDataValue); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Expressions/ValueValidator.cs.meta b/Editor/Tests/Validators/Expressions/ValueValidator.cs.meta new file mode 100644 index 0000000..192e7c7 --- /dev/null +++ b/Editor/Tests/Validators/Expressions/ValueValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e525637262f5bba4c91bb7963fcf5d4e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Expressions/VariableReferenceValidator.cs b/Editor/Tests/Validators/Expressions/VariableReferenceValidator.cs new file mode 100644 index 0000000..f7022f8 --- /dev/null +++ b/Editor/Tests/Validators/Expressions/VariableReferenceValidator.cs @@ -0,0 +1,24 @@ +using PatchManager.SassyPatching.Nodes.Expressions; + +namespace PatchManager.SassyPatching.Tests.Validators.Expressions +{ + /// + /// Describes a validator for matching nodes of type + /// + public class VariableReferenceValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string VariableName = ""; + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(VariableReference node) + { + return node.VariableName == VariableName; + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Expressions/VariableReferenceValidator.cs.meta b/Editor/Tests/Validators/Expressions/VariableReferenceValidator.cs.meta new file mode 100644 index 0000000..9ba0b46 --- /dev/null +++ b/Editor/Tests/Validators/Expressions/VariableReferenceValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a5ac2470d530bdf44a2536abe43e39c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/FalseValidator.cs b/Editor/Tests/Validators/FalseValidator.cs new file mode 100644 index 0000000..28d5bf2 --- /dev/null +++ b/Editor/Tests/Validators/FalseValidator.cs @@ -0,0 +1,17 @@ +using PatchManager.SassyPatching.Nodes; + +namespace PatchManager.SassyPatching.Tests.Validators +{ + /// + /// Describes a validator that never matches + /// + public class FalseValidator : ParseValidator + { + /// + /// Given any node, it does not match + /// + /// Ignored + /// False + public override bool Validate(Node node) => false; + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/FalseValidator.cs.meta b/Editor/Tests/Validators/FalseValidator.cs.meta new file mode 100644 index 0000000..d253caf --- /dev/null +++ b/Editor/Tests/Validators/FalseValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 35e5c6742a5f000429e1feec6b516b45 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/KeyValueValidator.cs b/Editor/Tests/Validators/KeyValueValidator.cs new file mode 100644 index 0000000..e34decc --- /dev/null +++ b/Editor/Tests/Validators/KeyValueValidator.cs @@ -0,0 +1,25 @@ +using PatchManager.SassyPatching.Nodes; + +namespace PatchManager.SassyPatching.Tests.Validators +{ + /// + /// Describes a validator for matching nodes of type + /// + public class KeyValueValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string Key = ""; + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator Value = new FalseValidator(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(KeyValueNode node) => node.Key == Key && Value.Validate(node.Value); + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/KeyValueValidator.cs.meta b/Editor/Tests/Validators/KeyValueValidator.cs.meta new file mode 100644 index 0000000..f39dcf9 --- /dev/null +++ b/Editor/Tests/Validators/KeyValueValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0eb4913e958bd064c865443041623eba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/ParseValidator.cs b/Editor/Tests/Validators/ParseValidator.cs new file mode 100644 index 0000000..20b62ab --- /dev/null +++ b/Editor/Tests/Validators/ParseValidator.cs @@ -0,0 +1,37 @@ +using PatchManager.SassyPatching.Nodes; +namespace PatchManager.SassyPatching.Tests.Validators +{ + /// + /// An abstract base class for validators that describe a tree structure for the results of a transformation to be matched against for validation + /// + public abstract class ParseValidator + { + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public abstract bool Validate(Node node); + } + + /// + /// A generic extension to where it has a specific type of that the tree described by the validator will match against + /// + /// The type of to match against + public abstract class ParseValidator : ParseValidator where T : Node + { + /// + /// An override of that validates whether the node is of the type that this matches against + /// + /// The node to match against + /// True if the node is of the type of node that this validator matches against and if the node matches against the tree defined by this validator + public sealed override bool Validate(Node node) => node is T tNode && Validate(tNode); + + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public abstract bool Validate(T node); + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/ParseValidator.cs.meta b/Editor/Tests/Validators/ParseValidator.cs.meta new file mode 100644 index 0000000..459af57 --- /dev/null +++ b/Editor/Tests/Validators/ParseValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e9aef8ba3b713eb4987cd6a637ff6aed +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/PatchValidator.cs b/Editor/Tests/Validators/PatchValidator.cs new file mode 100644 index 0000000..fcba406 --- /dev/null +++ b/Editor/Tests/Validators/PatchValidator.cs @@ -0,0 +1,50 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes; + +namespace PatchManager.SassyPatching.Tests.Validators +{ + /// + /// Describes a validator for matching nodes of type + /// + public class PatchValidator : ParseValidator, IEnumerable + { + private readonly List _validators = new(); + + + /// + /// Gets an enumerator that enumerates over the validators contained in this validator + /// + /// The enumerator that enumerates over the validators contained in this validator + public IEnumerator GetEnumerator() + { + return _validators.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(SassyPatch node) + { + if (node.Children.Count != _validators.Count) return false; + return !_validators.Where((t, i) => !t.Validate(node.Children[i])).Any(); + } + + /// + /// Adds a validator to the children of the tree that this validator describes + /// + /// The child validator that should be added to the end as a child of this validator + public void Add(ParseValidator parseValidator) + { + _validators.Add(parseValidator); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/PatchValidator.cs.meta b/Editor/Tests/Validators/PatchValidator.cs.meta new file mode 100644 index 0000000..a21f5cc --- /dev/null +++ b/Editor/Tests/Validators/PatchValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1e7a46046f5ecc043a9dd1ba669d6a03 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Selectors.meta b/Editor/Tests/Validators/Selectors.meta new file mode 100644 index 0000000..ae3cae6 --- /dev/null +++ b/Editor/Tests/Validators/Selectors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 084bc3e8fccc0e747a5ff41e5d2af47e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Selectors/ChildSelectorValidator.cs b/Editor/Tests/Validators/Selectors/ChildSelectorValidator.cs new file mode 100644 index 0000000..c8ab420 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/ChildSelectorValidator.cs @@ -0,0 +1,24 @@ +using PatchManager.SassyPatching.Nodes.Selectors; + +namespace PatchManager.SassyPatching.Tests.Validators.Selectors +{ + /// + /// Describes a validator for matching nodes of type + /// + public class ChildSelectorValidator : ParseValidator + { /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator Parent = new FalseValidator(); + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator Child = new FalseValidator(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(ChildSelector node) => Parent.Validate(node.Parent) && Child.Validate(node.Child); + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Selectors/ChildSelectorValidator.cs.meta b/Editor/Tests/Validators/Selectors/ChildSelectorValidator.cs.meta new file mode 100644 index 0000000..79ba4c9 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/ChildSelectorValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c1814ad2f51ce6d45b824fe1eb6cdaff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Selectors/ClassSelectorValidator.cs b/Editor/Tests/Validators/Selectors/ClassSelectorValidator.cs new file mode 100644 index 0000000..9489f84 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/ClassSelectorValidator.cs @@ -0,0 +1,21 @@ +using PatchManager.SassyPatching.Nodes.Selectors; + +namespace PatchManager.SassyPatching.Tests.Validators.Selectors +{ + /// + /// Describes a validator for matching nodes of type + /// + public class ClassSelectorValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string ClassName = ""; + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(ClassSelector node) => node.ClassName == ClassName; + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Selectors/ClassSelectorValidator.cs.meta b/Editor/Tests/Validators/Selectors/ClassSelectorValidator.cs.meta new file mode 100644 index 0000000..2802ddd --- /dev/null +++ b/Editor/Tests/Validators/Selectors/ClassSelectorValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d09de10e7017bba4a82259e61343e99c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Selectors/CombinationSelectorValidator.cs b/Editor/Tests/Validators/Selectors/CombinationSelectorValidator.cs new file mode 100644 index 0000000..61a14ed --- /dev/null +++ b/Editor/Tests/Validators/Selectors/CombinationSelectorValidator.cs @@ -0,0 +1,45 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes.Selectors; + +namespace PatchManager.SassyPatching.Tests.Validators.Selectors +{ + /// + /// Describes a validator for matching nodes of type + /// + public class CombinationSelectorValidator : ParseValidator, IEnumerable + { + private readonly List _validators = new(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(CombinationSelector node) + { + if (_validators.Count != node.Selectors.Count) return false; + return !_validators.Where((x, y) => !x.Validate(node.Selectors[y])).Any(); + } + + /// + /// Gets an enumerator that enumerates over the validators contained in this validator + /// + /// The enumerator that enumerates over the validators contained in this validator + public IEnumerator GetEnumerator() + { + return _validators.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Adds a validator to the children of the tree that this validator describes + /// + /// The child validator that should be added to the end as a child of this validator + public void Add(ParseValidator validator) => _validators.Add(validator); + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Selectors/CombinationSelectorValidator.cs.meta b/Editor/Tests/Validators/Selectors/CombinationSelectorValidator.cs.meta new file mode 100644 index 0000000..c3056e9 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/CombinationSelectorValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a60dc6d92060a26448e5c797c4346a39 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Selectors/ElementSelectorValidator.cs b/Editor/Tests/Validators/Selectors/ElementSelectorValidator.cs new file mode 100644 index 0000000..f6b3d67 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/ElementSelectorValidator.cs @@ -0,0 +1,21 @@ +using PatchManager.SassyPatching.Nodes.Selectors; + +namespace PatchManager.SassyPatching.Tests.Validators.Selectors +{ + /// + /// Describes a validator for matching nodes of type + /// + public class ElementSelectorValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string ElementName = ""; + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(ElementSelector node) => node.ElementName == ElementName; + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Selectors/ElementSelectorValidator.cs.meta b/Editor/Tests/Validators/Selectors/ElementSelectorValidator.cs.meta new file mode 100644 index 0000000..54b88d6 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/ElementSelectorValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ba3e5456f2d6faa48911368d922251c8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Selectors/IntersectionSelectorValidator.cs b/Editor/Tests/Validators/Selectors/IntersectionSelectorValidator.cs new file mode 100644 index 0000000..92dc101 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/IntersectionSelectorValidator.cs @@ -0,0 +1,44 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes.Selectors; + +namespace PatchManager.SassyPatching.Tests.Validators.Selectors +{ + /// + /// Describes a validator for matching nodes of type + /// + public class IntersectionSelectorValidator : ParseValidator, IEnumerable + { + private readonly List _validators = new(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(IntersectionSelector node) + { + if (_validators.Count != node.Selectors.Count) return false; + return !_validators.Where((x, y) => !x.Validate(node.Selectors[y])).Any(); + } + /// + /// Gets an enumerator that enumerates over the validators contained in this validator + /// + /// The enumerator that enumerates over the validators contained in this validator + public IEnumerator GetEnumerator() + { + return _validators.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Adds a validator to the children of the tree that this validator describes + /// + /// The child validator that should be added to the end as a child of this validator + public void Add(ParseValidator validator) => _validators.Add(validator); + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Selectors/IntersectionSelectorValidator.cs.meta b/Editor/Tests/Validators/Selectors/IntersectionSelectorValidator.cs.meta new file mode 100644 index 0000000..2f6890e --- /dev/null +++ b/Editor/Tests/Validators/Selectors/IntersectionSelectorValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e9e768af61544a04fb27801a8f6be08d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Selectors/NameSelectorValidator.cs b/Editor/Tests/Validators/Selectors/NameSelectorValidator.cs new file mode 100644 index 0000000..0e06c16 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/NameSelectorValidator.cs @@ -0,0 +1,21 @@ +using PatchManager.SassyPatching.Nodes.Selectors; + +namespace PatchManager.SassyPatching.Tests.Validators.Selectors +{ + /// + /// Describes a validator for matching nodes of type + /// + public class NameSelectorValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string NamePattern = ""; + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(NameSelector node) => node.NamePattern == NamePattern; + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Selectors/NameSelectorValidator.cs.meta b/Editor/Tests/Validators/Selectors/NameSelectorValidator.cs.meta new file mode 100644 index 0000000..d3ebd05 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/NameSelectorValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 037f93f6adf6467488f3d329c9a708b0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Selectors/RulesetSelectorValidator.cs b/Editor/Tests/Validators/Selectors/RulesetSelectorValidator.cs new file mode 100644 index 0000000..fd750c2 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/RulesetSelectorValidator.cs @@ -0,0 +1,21 @@ +using PatchManager.SassyPatching.Nodes.Selectors; + +namespace PatchManager.SassyPatching.Tests.Validators.Selectors +{ + /// + /// Describes a validator for matching nodes of type + /// + public class RulesetSelectorValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string RulesetName = ""; + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(RulesetSelector node) => node.RulesetName == RulesetName; + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Selectors/RulesetSelectorValidator.cs.meta b/Editor/Tests/Validators/Selectors/RulesetSelectorValidator.cs.meta new file mode 100644 index 0000000..a558a68 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/RulesetSelectorValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1f5212fe25a05c642bd1553064a4950a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Selectors/WildcardSelectorValidator.cs b/Editor/Tests/Validators/Selectors/WildcardSelectorValidator.cs new file mode 100644 index 0000000..86c1103 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/WildcardSelectorValidator.cs @@ -0,0 +1,17 @@ +using PatchManager.SassyPatching.Nodes.Selectors; + +namespace PatchManager.SassyPatching.Tests.Validators.Selectors +{ + /// + /// Describes a validator for matching nodes of type + /// + public class WildcardSelectorValidator : ParseValidator + { + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(WildcardSelector node) => true; + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Selectors/WildcardSelectorValidator.cs.meta b/Editor/Tests/Validators/Selectors/WildcardSelectorValidator.cs.meta new file mode 100644 index 0000000..40411ef --- /dev/null +++ b/Editor/Tests/Validators/Selectors/WildcardSelectorValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 11555cf1db1d53649979f289e6a88d7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Selectors/WithoutClassSelectorValidator.cs b/Editor/Tests/Validators/Selectors/WithoutClassSelectorValidator.cs new file mode 100644 index 0000000..5494e57 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/WithoutClassSelectorValidator.cs @@ -0,0 +1,21 @@ +using PatchManager.SassyPatching.Nodes.Selectors; + +namespace PatchManager.SassyPatching.Tests.Validators.Selectors +{ + /// + /// Describes a validator for matching nodes of type + /// + public class WithoutClassSelectorValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string ClassName = ""; + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(WithoutClassSelector node) => node.ClassName == ClassName; + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Selectors/WithoutClassSelectorValidator.cs.meta b/Editor/Tests/Validators/Selectors/WithoutClassSelectorValidator.cs.meta new file mode 100644 index 0000000..c553bfd --- /dev/null +++ b/Editor/Tests/Validators/Selectors/WithoutClassSelectorValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 05f7fa6fd3a8f22499de5edb780839a2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Selectors/WithoutNameSelectorValidator.cs b/Editor/Tests/Validators/Selectors/WithoutNameSelectorValidator.cs new file mode 100644 index 0000000..8f8ef17 --- /dev/null +++ b/Editor/Tests/Validators/Selectors/WithoutNameSelectorValidator.cs @@ -0,0 +1,21 @@ +using PatchManager.SassyPatching.Nodes.Selectors; + +namespace PatchManager.SassyPatching.Tests.Validators.Selectors +{ + /// + /// Describes a validator for matching nodes of type + /// + public class WithoutNameSelectorValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string NamePattern = ""; + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(WithoutNameSelector node) => node.NamePattern == NamePattern; + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Selectors/WithoutNameSelectorValidator.cs.meta b/Editor/Tests/Validators/Selectors/WithoutNameSelectorValidator.cs.meta new file mode 100644 index 0000000..b2bccfe --- /dev/null +++ b/Editor/Tests/Validators/Selectors/WithoutNameSelectorValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a3c6b0a5e1bb36a4b845bc6d05b81c3c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements.meta b/Editor/Tests/Validators/Statements.meta new file mode 100644 index 0000000..45e812f --- /dev/null +++ b/Editor/Tests/Validators/Statements.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f9800177910f6b14f80cf43ae329fa3f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/ConditionalValidator.cs b/Editor/Tests/Validators/Statements/ConditionalValidator.cs new file mode 100644 index 0000000..481af06 --- /dev/null +++ b/Editor/Tests/Validators/Statements/ConditionalValidator.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes.Statements; + +namespace PatchManager.SassyPatching.Tests.Validators.Statements +{ + /// + /// Describes a validator for matching nodes of type + /// + public class ConditionalValidator : ParseValidator + { + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator Condition = new FalseValidator(); + /// + /// A list of validators used to match against the corresponding list of nodes in a value of type + /// + public List Body = new(); + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator Else = null; + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(Conditional node) + { + if (!Condition.Validate(node.Condition)) return false; + if (Body.Count != node.Body.Count) return false; + if (Body.Where((x, y) => !x.Validate(node.Body[y])).Any()) return false; + if (Else == null && node.Else == null) return true; + if (Else == null && node.Else != null) return false; + if (Else != null && node.Else == null) return false; + return Else!.Validate(node.Else!); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Statements/ConditionalValidator.cs.meta b/Editor/Tests/Validators/Statements/ConditionalValidator.cs.meta new file mode 100644 index 0000000..95d5927 --- /dev/null +++ b/Editor/Tests/Validators/Statements/ConditionalValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4dcd637f30ce9654b904f526a51f54de +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/FunctionLevel.meta b/Editor/Tests/Validators/Statements/FunctionLevel.meta new file mode 100644 index 0000000..687b014 --- /dev/null +++ b/Editor/Tests/Validators/Statements/FunctionLevel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c02ed983cde31e54fbfec88c495d8e48 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/FunctionLevel/ReturnValidator.cs b/Editor/Tests/Validators/Statements/FunctionLevel/ReturnValidator.cs new file mode 100644 index 0000000..21ae9a8 --- /dev/null +++ b/Editor/Tests/Validators/Statements/FunctionLevel/ReturnValidator.cs @@ -0,0 +1,24 @@ +using PatchManager.SassyPatching.Nodes.Statements.FunctionLevel; + +namespace PatchManager.SassyPatching.Tests.Validators.Statements.FunctionLevel +{ + /// + /// Describes a validator for matching nodes of type + /// + public class ReturnValidator : ParseValidator + { + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator ReturnedValue = new FalseValidator(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(Return node) + { + return ReturnedValue.Validate(node.ReturnedValue); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Statements/FunctionLevel/ReturnValidator.cs.meta b/Editor/Tests/Validators/Statements/FunctionLevel/ReturnValidator.cs.meta new file mode 100644 index 0000000..73b949d --- /dev/null +++ b/Editor/Tests/Validators/Statements/FunctionLevel/ReturnValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 166ecd50458c18445aa44f55396cf7f4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/SelectionBlockValidator.cs b/Editor/Tests/Validators/Statements/SelectionBlockValidator.cs new file mode 100644 index 0000000..e5001d0 --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionBlockValidator.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes.Statements; + +namespace PatchManager.SassyPatching.Tests.Validators.Statements +{ + /// + /// Describes a validator for matching nodes of type + /// + public class SelectionBlockValidator : ParseValidator + { + /// + /// A list of validators used to match against the corresponding list of nodes in a value of type + /// + public List Attributes = new(); + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator Selector = new FalseValidator(); + /// + /// A list of validators used to match against the corresponding list of nodes in a value of type + /// + public List Actions = new(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(SelectionBlock node) + { + if (Attributes.Count != node.Attributes.Count) return false; + if (Attributes.Where((x, y) => !x.Validate(node.Attributes[y])).Any()) return false; + if (!Selector.Validate(node.Selector)) return false; + if (Actions.Count != node.Actions.Count) return false; + return !Actions.Where((x, y) => !x.Validate(node.Actions[y])).Any(); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Statements/SelectionBlockValidator.cs.meta b/Editor/Tests/Validators/Statements/SelectionBlockValidator.cs.meta new file mode 100644 index 0000000..a6af4d1 --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionBlockValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bbc6c0d8c85dc334fba36ea843fe4896 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/SelectionLevel.meta b/Editor/Tests/Validators/Statements/SelectionLevel.meta new file mode 100644 index 0000000..8ac633a --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionLevel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 391560fb8ab012142a07b46149788f21 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/SelectionLevel/DeleteValueValidator.cs b/Editor/Tests/Validators/Statements/SelectionLevel/DeleteValueValidator.cs new file mode 100644 index 0000000..c26a9d5 --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionLevel/DeleteValueValidator.cs @@ -0,0 +1,17 @@ +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; + +namespace PatchManager.SassyPatching.Tests.Validators.Statements.SelectionLevel +{ + /// + /// Describes a validator for matching nodes of type + /// + public class DeleteValueValidator : ParseValidator + { + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(DeleteValue node) => true; + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Statements/SelectionLevel/DeleteValueValidator.cs.meta b/Editor/Tests/Validators/Statements/SelectionLevel/DeleteValueValidator.cs.meta new file mode 100644 index 0000000..ccc11b7 --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionLevel/DeleteValueValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 97cf2fb3e905989458e7d4fcbaccbcb1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/SelectionLevel/FieldValidator.cs b/Editor/Tests/Validators/Statements/SelectionLevel/FieldValidator.cs new file mode 100644 index 0000000..38b0c89 --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionLevel/FieldValidator.cs @@ -0,0 +1,36 @@ +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; + +namespace PatchManager.SassyPatching.Tests.Validators.Statements.SelectionLevel +{ + /// + /// Describes a validator for matching nodes of type + /// + public class FieldValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string FieldName = ""; + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator Indexer = null; + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator FieldValue = new FalseValidator(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(Field node) + { + if (FieldName != node.FieldName) return false; + // if (Indexer == null && node.Indexer != null) return false; + // if (Indexer != null && node.Indexer == null) return false; + // if (Indexer != null && node.Indexer != null && !Indexer.Validate(node.Indexer)) return false; + return FieldValue.Validate(node.FieldValue); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Statements/SelectionLevel/FieldValidator.cs.meta b/Editor/Tests/Validators/Statements/SelectionLevel/FieldValidator.cs.meta new file mode 100644 index 0000000..cf34039 --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionLevel/FieldValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c7fa141422b5804e99875e60a71251d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/SelectionLevel/MergeValueValidator.cs b/Editor/Tests/Validators/Statements/SelectionLevel/MergeValueValidator.cs new file mode 100644 index 0000000..13ad32d --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionLevel/MergeValueValidator.cs @@ -0,0 +1,21 @@ +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; + +namespace PatchManager.SassyPatching.Tests.Validators.Statements.SelectionLevel +{ + /// + /// Describes a validator for matching nodes of type + /// + public class MergeValueValidator : ParseValidator + { + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator Value = new FalseValidator(); + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(MergeValue node) => Value.Validate(node.Value); + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Statements/SelectionLevel/MergeValueValidator.cs.meta b/Editor/Tests/Validators/Statements/SelectionLevel/MergeValueValidator.cs.meta new file mode 100644 index 0000000..89a6c7b --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionLevel/MergeValueValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 873993d9ed777d94c807796fdd132ae8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/SelectionLevel/MixinIncludeValidator.cs b/Editor/Tests/Validators/Statements/SelectionLevel/MixinIncludeValidator.cs new file mode 100644 index 0000000..620b529 --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionLevel/MixinIncludeValidator.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; + +namespace PatchManager.SassyPatching.Tests.Validators.Statements.SelectionLevel +{ + /// + /// Describes a validator for matching nodes of type + /// + public class MixinIncludeValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string MixinName = ""; + + /// + /// A list of validators used to match against the corresponding list of nodes in a value of type + /// + // ReSharper disable once CollectionNeverUpdated.Global + public List Arguments = new(); + + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(MixinInclude node) + { + if (node.MixinName != MixinName) return false; + if (Arguments.Count != node.Arguments.Count) return false; + return !Arguments.Where((x, y) => !x.Validate(node.Arguments[y])).Any(); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Statements/SelectionLevel/MixinIncludeValidator.cs.meta b/Editor/Tests/Validators/Statements/SelectionLevel/MixinIncludeValidator.cs.meta new file mode 100644 index 0000000..8cc2433 --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionLevel/MixinIncludeValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f99a95a6028e1b444a372f7e03f8675e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/SelectionLevel/SetValueValidator.cs b/Editor/Tests/Validators/Statements/SelectionLevel/SetValueValidator.cs new file mode 100644 index 0000000..8b68e70 --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionLevel/SetValueValidator.cs @@ -0,0 +1,24 @@ +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; + +namespace PatchManager.SassyPatching.Tests.Validators.Statements.SelectionLevel +{ + /// + /// Describes a validator for matching nodes of type + /// + public class SetValueValidator : ParseValidator + { + + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator Value = new FalseValidator(); + + + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(SetValue node) => Value.Validate(node.Value); + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Statements/SelectionLevel/SetValueValidator.cs.meta b/Editor/Tests/Validators/Statements/SelectionLevel/SetValueValidator.cs.meta new file mode 100644 index 0000000..2c3b769 --- /dev/null +++ b/Editor/Tests/Validators/Statements/SelectionLevel/SetValueValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15250af0eae5506489b61f308f801bb5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/TopLevel.meta b/Editor/Tests/Validators/Statements/TopLevel.meta new file mode 100644 index 0000000..0d5582a --- /dev/null +++ b/Editor/Tests/Validators/Statements/TopLevel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c6c4fe620f522944496d50173d69204f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/TopLevel/FunctionValidator.cs b/Editor/Tests/Validators/Statements/TopLevel/FunctionValidator.cs new file mode 100644 index 0000000..e80da74 --- /dev/null +++ b/Editor/Tests/Validators/Statements/TopLevel/FunctionValidator.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes.Statements.TopLevel; + +namespace PatchManager.SassyPatching.Tests.Validators.Statements.TopLevel +{ + /// + /// Describes a validator for matching nodes of type + /// + public class FunctionValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string Name = ""; + + /// + /// A list of validators used to match against the corresponding list of nodes in a value of type + /// + public List Arguments = new(); + + /// + /// A list of validators used to match against the corresponding list of nodes in a value of type + /// + public List Body = new(); + + + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(Function node) + { + if (node.Name != Name) return false; + if (Arguments.Count != node.Arguments.Count) return false; + if (Arguments.Where((validator, idx) => !validator.Validate(node.Arguments[idx])).Any()) return false; + if (Body.Count != node.Body.Count) return false; + return !Body.Where((validator, idx) => !validator.Validate(node.Body[idx])).Any(); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Statements/TopLevel/FunctionValidator.cs.meta b/Editor/Tests/Validators/Statements/TopLevel/FunctionValidator.cs.meta new file mode 100644 index 0000000..cc9349a --- /dev/null +++ b/Editor/Tests/Validators/Statements/TopLevel/FunctionValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6a67457207ea3ee49b0e889201dc93e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/TopLevel/ImportValidator.cs b/Editor/Tests/Validators/Statements/TopLevel/ImportValidator.cs new file mode 100644 index 0000000..ca505d3 --- /dev/null +++ b/Editor/Tests/Validators/Statements/TopLevel/ImportValidator.cs @@ -0,0 +1,25 @@ +using PatchManager.SassyPatching.Nodes.Statements.TopLevel; + +namespace PatchManager.SassyPatching.Tests.Validators.Statements.TopLevel +{ + /// + /// Describes a validator for matching nodes of type + /// + public class ImportValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string Library = ""; + + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(Import node) + { + return node.Library == Library; + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Statements/TopLevel/ImportValidator.cs.meta b/Editor/Tests/Validators/Statements/TopLevel/ImportValidator.cs.meta new file mode 100644 index 0000000..22a443c --- /dev/null +++ b/Editor/Tests/Validators/Statements/TopLevel/ImportValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52355667d309c714f90c24d0263954ca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/TopLevel/MixinValidator.cs b/Editor/Tests/Validators/Statements/TopLevel/MixinValidator.cs new file mode 100644 index 0000000..21f4e52 --- /dev/null +++ b/Editor/Tests/Validators/Statements/TopLevel/MixinValidator.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; +using System.Linq; +using PatchManager.SassyPatching.Nodes.Statements.TopLevel; + +namespace PatchManager.SassyPatching.Tests.Validators.Statements.TopLevel +{ + /// + /// Describes a validator for matching nodes of type + /// + public class MixinValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string Name = ""; + + /// + /// A list of validators used to match against the corresponding list of nodes in a value of type + /// + public List Arguments = new(); + + /// + /// A list of validators used to match against the corresponding list of nodes in a value of type + /// + public List Body = new(); + + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(Mixin node) + { + if (node.Name != Name) return false; + if (Arguments.Count != node.Arguments.Count) return false; + if (Arguments.Where((validator, idx) => !validator.Validate(node.Arguments[idx])).Any()) return false; + if (Body.Count != node.Body.Count) return false; + return !Body.Where((validator, idx) => !validator.Validate(node.Body[idx])).Any(); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Statements/TopLevel/MixinValidator.cs.meta b/Editor/Tests/Validators/Statements/TopLevel/MixinValidator.cs.meta new file mode 100644 index 0000000..5a251e0 --- /dev/null +++ b/Editor/Tests/Validators/Statements/TopLevel/MixinValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37a3ba4ccd3310b4bb3ad5f5b75d493d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Tests/Validators/Statements/VariableDeclarationValidator.cs b/Editor/Tests/Validators/Statements/VariableDeclarationValidator.cs new file mode 100644 index 0000000..e2acdac --- /dev/null +++ b/Editor/Tests/Validators/Statements/VariableDeclarationValidator.cs @@ -0,0 +1,30 @@ +using PatchManager.SassyPatching.Nodes.Statements; + +namespace PatchManager.SassyPatching.Tests.Validators.Statements +{ + /// + /// Describes a validator for matching nodes of type + /// + public class VariableDeclarationValidator : ParseValidator + { + /// + /// A field that is used to match against the corresponding field in a node of type + /// + public string Variable = ""; + /// + /// A validator that is used to match against the corresponding node in a node of type + /// + public ParseValidator Value = new FalseValidator(); + + /// + /// Determines if a node matches the tree defined by this validator + /// + /// The node to match against + /// True if the node matches against the tree defined by this validator + public override bool Validate(VariableDeclaration node) + { + if (node.Variable != Variable) return false; + return Value.Validate(node.Value); + } + } +} \ No newline at end of file diff --git a/Editor/Tests/Validators/Statements/VariableDeclarationValidator.cs.meta b/Editor/Tests/Validators/Statements/VariableDeclarationValidator.cs.meta new file mode 100644 index 0000000..fa9f558 --- /dev/null +++ b/Editor/Tests/Validators/Statements/VariableDeclarationValidator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 22e55bd866a4fae40b9614c810d04979 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/LICENSE.meta b/LICENSE.meta new file mode 100644 index 0000000..66005d9 --- /dev/null +++ b/LICENSE.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c49c47a75bd1ea1469c48784f5f36ce4 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Package.nuspec.meta b/Package.nuspec.meta new file mode 100644 index 0000000..62d9c2c --- /dev/null +++ b/Package.nuspec.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 94dba55fd1c17584d92cb8b09d578719 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/PatchManager.sln.DotSettings.meta b/PatchManager.sln.DotSettings.meta new file mode 100644 index 0000000..11b2ec9 --- /dev/null +++ b/PatchManager.sln.DotSettings.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9f629224d5c350047b1ff7f960ca8deb +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/PatchManager.sln.meta b/PatchManager.sln.meta new file mode 100644 index 0000000..6cbe872 --- /dev/null +++ b/PatchManager.sln.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 09e8be82ad60cc844a265cc3d36649c5 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/README.md.meta b/README.md.meta new file mode 100644 index 0000000..116427f --- /dev/null +++ b/README.md.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9f36ace5fcad2854ea92aba74aaf5804 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime.meta b/Runtime.meta new file mode 100644 index 0000000..f5e1c16 --- /dev/null +++ b/Runtime.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1edc688aefb34ca892eb435b772a80af +timeCreated: 1739382210 \ No newline at end of file diff --git a/Runtime/Core.meta b/Runtime/Core.meta new file mode 100644 index 0000000..555f0f1 --- /dev/null +++ b/Runtime/Core.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: a05984da072b4ca8a52ec0c165c23953 +timeCreated: 1739382514 \ No newline at end of file diff --git a/Runtime/Core/Assets.meta b/Runtime/Core/Assets.meta new file mode 100644 index 0000000..022af09 --- /dev/null +++ b/Runtime/Core/Assets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 477f380cc196cc740aa585c536a1f78a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Assets/ArchiveResourceLocator.cs b/Runtime/Core/Assets/ArchiveResourceLocator.cs new file mode 100644 index 0000000..d5b1ef0 --- /dev/null +++ b/Runtime/Core/Assets/ArchiveResourceLocator.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using PatchManager.Core.Cache; +using PatchManager.Shared; +using UniLinq; +using UnityEngine; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.ResourceManagement.ResourceLocations; + +namespace PatchManager.Core.Assets +{ + /// + /// Locates assets in archives of cached assets. + /// + internal class ArchiveResourceLocator : IResourceLocator + { + /// + /// The ID of the locator. + /// + public string LocatorId => GetType().FullName; + + /// + /// The labels registered in the locator. + /// + public IEnumerable Keys => CacheManager.Inventory.CacheEntries.Keys; + + /// + /// Locates an asset file in a cache archive by its label and type. + /// + /// Label to find. + /// Type of assets to find. + /// List of found locations. + /// + public bool Locate(object key, Type type, out IList locations) + { + var label = key.ToString(); + if (!CacheManager.Inventory.CacheEntries.TryGetValue(label, out var cacheEntry)) + { + locations = new List(); + return false; + } + + locations = cacheEntry.Assets + .Select(asset => new ResourceLocationBase( + cacheEntry.ArchiveFilename, + asset, + typeof(ArchiveResourceProvider).FullName, + typeof(TextAsset) + )) + .Cast() + .ToList(); + + if (locations.Count == 0) + { + return false; + } + + Logging.LogDebug($"Located key '{key}' with {locations.Count} locations."); + return true; + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Assets/ArchiveResourceLocator.cs.meta b/Runtime/Core/Assets/ArchiveResourceLocator.cs.meta new file mode 100644 index 0000000..cdff3c2 --- /dev/null +++ b/Runtime/Core/Assets/ArchiveResourceLocator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d93b6d7501b3d304f885968fa3f00835 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Assets/ArchiveResourceProvider.cs b/Runtime/Core/Assets/ArchiveResourceProvider.cs new file mode 100644 index 0000000..78ba12f --- /dev/null +++ b/Runtime/Core/Assets/ArchiveResourceProvider.cs @@ -0,0 +1,41 @@ +using System; +using System.IO; +using PatchManager.Core.Cache; +using PatchManager.Shared; +using UnityEngine; +using UnityEngine.ResourceManagement.ResourceProviders; + +namespace PatchManager.Core.Assets +{ + /// + /// Provides assets found by . + /// + internal class ArchiveResourceProvider : ResourceProviderBase + { + /// + /// Provides assets found by . + /// + /// Information about the asset to be provided. + public override void Provide(ProvideHandle provideHandle) + { + try + { + var archiveName = provideHandle.Location.PrimaryKey; + var file = provideHandle.Location.InternalId; + Logging.LogDebug($"Loading {archiveName}/{file}"); + + var archive = CacheManager.GetArchive(archiveName); + var asset = new TextAsset(archive.ReadFile(file)) + { + name = Path.GetFileName(file) + }; + provideHandle.Complete(asset, true, null); + } + catch (Exception e) + { + Logging.LogError(e); + provideHandle.Complete(null, false, e); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Assets/ArchiveResourceProvider.cs.meta b/Runtime/Core/Assets/ArchiveResourceProvider.cs.meta new file mode 100644 index 0000000..01c547f --- /dev/null +++ b/Runtime/Core/Assets/ArchiveResourceProvider.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c07595b570f39de4b9986230d7f9ed5c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Assets/Locators.cs b/Runtime/Core/Assets/Locators.cs new file mode 100644 index 0000000..911c5d4 --- /dev/null +++ b/Runtime/Core/Assets/Locators.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.AddressableAssets.ResourceLocators; +using UnityEngine.ResourceManagement.ResourceLocations; + +namespace PatchManager.Core.Assets +{ + /// + /// A class that holds all the custom resource locators for patched asset files. + /// + public static class Locators + { + private static readonly List ResourceLocators = new(); + + /// + /// Register a custom resource locator. + /// + /// Locator to register. + public static void Register(IResourceLocator locator) + { + ResourceLocators.Add(locator); + } + + /// + /// Locate assets by label. + /// + /// Label of the assets to be located. + /// List of locations of the found assets. + /// True if any assets were found, false otherwise. + public static bool LocateAll(object label, out List locations) + { + locations = new List(); + foreach (var locator in ResourceLocators) + { + locator.Locate(label, typeof(TextAsset), out var foundLocations); + locations.AddRange(foundLocations); + } + + return locations.Count > 0; + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Assets/Locators.cs.meta b/Runtime/Core/Assets/Locators.cs.meta new file mode 100644 index 0000000..2a05169 --- /dev/null +++ b/Runtime/Core/Assets/Locators.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: de4afab26afe68a46a17cedac3cf8247 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Assets/PatchingManager.cs b/Runtime/Core/Assets/PatchingManager.cs new file mode 100644 index 0000000..86f571d --- /dev/null +++ b/Runtime/Core/Assets/PatchingManager.cs @@ -0,0 +1,367 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using KSP.Game; +using KSP.Game.Flow; +using PatchManager.Core.Cache; +using PatchManager.Core.Cache.Json; +using PatchManager.Core.Utility; +using PatchManager.SassyPatching.Execution; +using PatchManager.Shared; +using PatchManager.Shared.Interfaces; +using SpaceWarp.API.Mods; +using UniLinq; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.ResourceManagement.AsyncOperations; + +namespace PatchManager.Core.Assets +{ + internal static class PatchingManager + { + internal static readonly List Patchers = new(); + internal static readonly List Generators = new(); + internal static Universe Universe; + + private static readonly PatchHashes CurrentPatchHashes = PatchHashes.CreateDefault(); + + private static int _initialLibraryCount; + private static Dictionary> _createdAssets = new(); + + internal static int TotalPatchCount; + internal static int TotalErrorCount; + + public static void GenerateUniverse(HashSet singleFileModIds) + { + var loadedPlugins = PluginList.AllEnabledAndActivePlugins.Select(x => x.Guid).ToList(); + loadedPlugins.AddRange(singleFileModIds); + Universe = new(RegisterPatcher, Logging.LogError, Logging.LogMessage, RegisterGenerator, + loadedPlugins); + _initialLibraryCount = Universe.AllLibraries.Count; + } + + private static void RegisterPatcher(ITextPatcher patcher) + { + for (var index = 0; index < Patchers.Count; index++) + { + if (Patchers[index].Priority <= patcher.Priority) + { + continue; + } + + Patchers.Insert(index, patcher); + return; + } + + Patchers.Add(patcher); + } + + private static void RegisterGenerator(ITextAssetGenerator generator) + { + for (var index = 0; index < Generators.Count; index++) + { + if (Generators[index].Priority <= generator.Priority) + { + continue; + } + + Generators.Insert(index, generator); + return; + } + + Generators.Add(generator); + } + + private static string PatchJson(string label, string assetName, string text) + { + Console.WriteLine($"Patching {label}:{assetName}"); + var patchCount = 0; + + foreach (var patcher in Patchers) + { + var backup = text; + try + { + var wasPatched = patcher.TryPatch(label, assetName, ref text); + if (wasPatched) + { + patchCount++; + } + } + catch (Exception e) + { + TotalErrorCount += 1; + Console.WriteLine($"Patch of {label}:{assetName} errored due to: {e}"); + text = backup; + } + + if (text == "") + { + break; + } + } + + TotalPatchCount += patchCount; + if (patchCount > 0) + { + Console.WriteLine($"Patched {label}:{assetName} with {patchCount} patches. Total: {TotalPatchCount}"); + } + + return text; + } + + private static int _previousLibraryCount = -1; + + public static void ImportModPatches(string modName, string modFolder) + { + Universe.LoadPatchesInDirectory(new DirectoryInfo(modFolder), modName); + + var currentLibraryCount = Universe.AllLibraries.Count - _initialLibraryCount; + + if (currentLibraryCount > _previousLibraryCount) + { + Logging.LogInfo($"{currentLibraryCount} mod libraries loaded!"); + _previousLibraryCount++; + } + + var patchFiles = Directory.GetFiles(modFolder, "*.patch", SearchOption.AllDirectories); + foreach (var patchFile in patchFiles) + { + var patchHash = Hash.FromFile(patchFile); + CurrentPatchHashes.Patches.Add(patchFile, patchHash); + } + } + + public static void ImportSinglePatch(FileInfo fileInfo) + { + Universe.LoadSinglePatchFile(fileInfo, new DirectoryInfo(".")); + CurrentPatchHashes.Patches.Add(fileInfo.FullName, Hash.FromFile(fileInfo.FullName)); + } + + public static void ImportAssetPatch(TextAsset asset, string modId) + { + Universe.LoadPatchAsset(asset, modId); + CurrentPatchHashes.Patches.Add(asset.name, Hash.FromString(asset.text)); + } + + public static void RegisterPatches() + { + Logging.LogInfo($"Registering all patches!"); + Universe.RegisterAllPatches(); + Logging.LogInfo($"{Patchers.Count} patchers registered!"); + Logging.LogInfo($"{Generators.Count} generators registered!"); + } + + /// + /// Invalidates the cache if the checksum is different. + /// + /// True if the cache is valid, false if it was invalidated. + public static bool InvalidateCacheIfNeeded() + { + var checksum = Hash.FromJsonObject(CurrentPatchHashes); + + if (CacheManager.Inventory.Checksum == checksum) + { + Logging.LogInfo("Cache is valid, skipping rebuild."); + CacheManager.CacheValidLabels.AddRange(CacheManager.Inventory.CacheEntries.Keys); + return true; + } + + Logging.LogInfo("Cache is invalid, rebuilding."); + CacheManager.InvalidateCache(); + CacheManager.Inventory.Checksum = checksum; + CacheManager.Inventory.Patches = CurrentPatchHashes; + + return false; + } + + private static AsyncOperationHandle> RebuildCache(string label) + { + Logging.LogInfo($"Patching: {label}"); + var archiveFilename = $"{label.Replace("/", "")}.zip"; + + var archiveFiles = new Dictionary(); + + var labelCacheEntry = new CacheEntry + { + Label = label, + ArchiveFilename = archiveFilename, + Assets = new List() + }; + var assetsCacheEntries = new Dictionary(); + var unchanged = !_createdAssets.ContainsKey(label); + + + if (_createdAssets.TryGetValue(label, out var createdAsset)) + { + foreach (var (name, text) in createdAsset) + { + var patchedText = PatchJson(label, name, text); + if (patchedText == "") continue; + archiveFiles[name] = patchedText; + labelCacheEntry.Assets.Add(name); + assetsCacheEntries.Add(name, new CacheEntry + { + Label = name, + ArchiveFilename = archiveFilename, + Assets = new List { name } + }); + } + + createdAsset.Clear(); + _createdAssets.Remove(label); + } + + var handle = Addressables.LoadAssetsAsync(label, asset => + { + try + { + var patchedText = PatchJson(label, asset.name, asset.text); + if (patchedText != asset.text) + { + unchanged = false; + } + + // Handle deletion + if (patchedText == "") + { + return; + } + + archiveFiles[asset.name] = patchedText; + labelCacheEntry.Assets.Add(asset.name); + assetsCacheEntries.Add(asset.name, new CacheEntry + { + Label = asset.name, + ArchiveFilename = archiveFilename, + Assets = new List { asset.name } + }); + } + catch (Exception e) + { + Console.WriteLine($"Unable to patch {asset.name} due to: {e.Message}"); + } + }); + + + void SaveArchive() + { + var archive = CacheManager.CreateArchive(archiveFilename); + foreach (var archiveFile in archiveFiles) + { + archive.AddFile(archiveFile.Key, archiveFile.Value); + } + + archive.Save(); + + CacheManager.CacheValidLabels.Add(label); + CacheManager.Inventory.CacheEntries.Add(label, labelCacheEntry); + CacheManager.Inventory.CacheEntries.AddRangeUnique(assetsCacheEntries); + CacheManager.SaveInventory(); + + Console.WriteLine($"Cache for label '{label}' rebuilt."); + } + + if (handle.Status == AsyncOperationStatus.Failed && !unchanged) + { + SaveArchive(); + } + + handle.Completed += results => + { + if (results.Status != AsyncOperationStatus.Succeeded || unchanged) + { + return; + } + + SaveArchive(); + Addressables.Release(results); + }; + + return handle; + } + + public static void CreateNewAssets(Action resolve, Action reject) + { + foreach (var generator in Generators) + { + try + { + var text = generator.Create(out var label, out var name); + Logging.LogDebug($"Generated an asset with the label {label}, and name {name}:\n{text}"); + + if (!_createdAssets.ContainsKey(label)) + _createdAssets[label] = new List<(string name, string text)>(); + _createdAssets[label].Add((name, text)); + } + catch (Exception e) + { + Logging.LogError($"Failed to generate an asset due to: {e}"); + } + } + + resolve(); + } + + internal static bool InjectPatchManagerTips = false; + + public static void RebuildAllCache(Action resolve, Action reject) + { + var distinctKeys = Universe.LoadedLabels.Concat(_createdAssets.Keys).Distinct().ToList(); + + InjectPatchManagerTips = true; + + GenericFlowAction CreateIndexedFlowAction(int idx) + { + return new GenericFlowAction( + $"Patch Manager: {distinctKeys[idx]}", + (resolve2, _) => + { + var handle = RebuildCache(distinctKeys[idx]); + var killTips = false; + if (idx + 1 < distinctKeys.Count) + { + GameManager.Instance.LoadingFlow.FlowActions.Insert( + GameManager.Instance.LoadingFlow.flowIndex + 1, + CreateIndexedFlowAction(idx + 1) + ); + } + else + { + killTips = true; + } + + CoroutineUtil.Instance.DoCoroutine(WaitForCacheRebuildSingleHandle(handle, resolve2, killTips)); + }); + } + + if (distinctKeys.Count > 0) + { + GameManager.Instance.LoadingFlow.FlowActions.Insert( + GameManager.Instance.LoadingFlow.flowIndex + 1, + CreateIndexedFlowAction(0) + ); + } + + resolve(); + } + + private static IEnumerator WaitForCacheRebuildSingleHandle( + AsyncOperationHandle> handle, + Action resolve, + bool killLoadingBarTips + ) + { + while (!handle.IsDone) + { + // "Shuffle" it + GameManager.Instance.Game.UI.LoadingBar.ShuffleLoadingTip(); + yield return null; + } + + InjectPatchManagerTips = !killLoadingBarTips; + resolve(); + } + } +} diff --git a/Runtime/Core/Assets/PatchingManager.cs.meta b/Runtime/Core/Assets/PatchingManager.cs.meta new file mode 100644 index 0000000..cd82cc9 --- /dev/null +++ b/Runtime/Core/Assets/PatchingManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bea87d6a1e0f1334f9b4467f42e4f162 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Cache.meta b/Runtime/Core/Cache.meta new file mode 100644 index 0000000..1a9591a --- /dev/null +++ b/Runtime/Core/Cache.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 53ad6f04a79afe348ac3b3d3a8318240 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Cache/Archive.cs b/Runtime/Core/Cache/Archive.cs new file mode 100644 index 0000000..1dca355 --- /dev/null +++ b/Runtime/Core/Cache/Archive.cs @@ -0,0 +1,114 @@ +using System; +using System.IO; +using System.IO.Compression; + +namespace PatchManager.Core.Cache +{ + /// + /// Wrapper for for use with the caching system. + /// + public class Archive : IDisposable + { + private readonly string _path; + private readonly MemoryStream _stream; + private bool _isDisposed; + + /// + /// Loads an archive from the given path into memory. + /// + /// Path to the archive file. + /// Whether to create a new archive if it does not exist. + public Archive(string path, bool createNew = false) + { + _path = path; + _stream = new MemoryStream(); + + if (!createNew) + { + using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read); + fileStream.CopyTo(_stream); + } + + _stream.Seek(0, SeekOrigin.Begin); + } + + /// + /// Disposes the archive object. + /// + public void Dispose() + { + if (_isDisposed) + { + return; + } + _stream.Dispose(); + _isDisposed = true; + + GC.SuppressFinalize(this); + } + + /// + /// Reads the content of the given file in the archive. + /// + /// Path of the file relative to the root of the archive. + /// The full text of the file. + /// Thrown when the file does not exist in the archive. + public string ReadFile(string filePath) + { + AssertNotDisposed(); + + using var archive = new ZipArchive(_stream, ZipArchiveMode.Read, true); + var entry = archive.GetEntry(filePath); + if (entry == null) + { + throw new FileNotFoundException($"File {filePath} does not exist in archive {_path}!"); + } + + using var stream = entry.Open(); + using var reader = new StreamReader(stream); + return reader.ReadToEnd(); + } + + /// + /// Adds a file to the archive. + /// + /// Path of the file relative to the root of the archive. + /// Content of the file. + /// Thrown when the file already exists in the archive. + public void AddFile(string filePath, string content) + { + AssertNotDisposed(); + + using var archive = new ZipArchive(_stream, ZipArchiveMode.Update, true); + + if (archive.GetEntry(filePath) != null) + { + throw new ArgumentException($"File {filePath} already exists in archive {_path}!"); + } + + var entry = archive.CreateEntry(filePath); + using var stream = entry.Open(); + using var writer = new StreamWriter(stream); + writer.Write(content); + } + + /// + /// Saves the archive to disk. + /// + public void Save() + { + AssertNotDisposed(); + using var fileStream = new FileStream(_path, FileMode.Create); + _stream.Seek(0, SeekOrigin.Begin); + _stream.CopyTo(fileStream); + } + + private void AssertNotDisposed() + { + if (_isDisposed) + { + throw new ObjectDisposedException(nameof(Archive), "The Archive object has been disposed."); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Cache/Archive.cs.meta b/Runtime/Core/Cache/Archive.cs.meta new file mode 100644 index 0000000..f85dd78 --- /dev/null +++ b/Runtime/Core/Cache/Archive.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9c0576347372de545ae1657ddcd5d8b7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Cache/CacheManager.cs b/Runtime/Core/Cache/CacheManager.cs new file mode 100644 index 0000000..8f03712 --- /dev/null +++ b/Runtime/Core/Cache/CacheManager.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using PatchManager.Core.Cache.Json; +using PatchManager.Shared; + +namespace PatchManager.Core.Cache +{ + internal static class CacheManager + { + /* + private static readonly string CacheDirectory = Path.Combine( + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, + "cache" + ); + */ + private const string CACHE_DIRECTORY = "./pm_cache"; + + private static readonly string InventoryPath = Path.Combine(CACHE_DIRECTORY, "inventory.json"); + + private static readonly Dictionary OpenArchives = new(); + public static readonly List CacheValidLabels = new(); + + private static Inventory _inventory; + public static Inventory Inventory => _inventory ??= Inventory.Load(InventoryPath); + + public static void CreateCacheFolderIfNotExists() + { + if (Directory.Exists(CACHE_DIRECTORY)) + { + return; + } + + Logging.LogDebug("Cache directory does not exist, creating a new one."); + Directory.CreateDirectory(CACHE_DIRECTORY); + } + + public static Archive CreateArchive(string archiveFilename) + { + var archivePath = Path.Combine(CACHE_DIRECTORY, archiveFilename); + if (File.Exists(archivePath)) + { + throw new ArgumentException($"Archive '{archivePath}' already exists!"); + } + + var archive = new Archive(archivePath, true); + OpenArchives.Add(archiveFilename, archive); + return archive; + } + + public static Archive GetArchive(string archiveFilename) + { + var archivePath = Path.Combine(CACHE_DIRECTORY, archiveFilename); + if (!File.Exists(archivePath)) + { + throw new FileNotFoundException($"Archive '{archivePath}' does not exist!"); + } + + if (!OpenArchives.ContainsKey(archiveFilename)) + { + OpenArchives.Add(archiveFilename, new Archive(archivePath)); + } + + return OpenArchives[archiveFilename]; + } + + public static void InvalidateCache() + { + CacheValidLabels.Clear(); + + _inventory = Inventory.Create(); + + foreach (var archive in OpenArchives.Values) + { + archive.Dispose(); + } + + OpenArchives.Clear(); + + Directory.Delete(CACHE_DIRECTORY, true); + CreateCacheFolderIfNotExists(); + } + + public static void SaveInventory() + { + Inventory.Save(InventoryPath); + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Cache/CacheManager.cs.meta b/Runtime/Core/Cache/CacheManager.cs.meta new file mode 100644 index 0000000..4c863c3 --- /dev/null +++ b/Runtime/Core/Cache/CacheManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3b356cfd2f4aaa345aff7bf6670ffdb8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Cache/Json.meta b/Runtime/Core/Cache/Json.meta new file mode 100644 index 0000000..458f330 --- /dev/null +++ b/Runtime/Core/Cache/Json.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f98750e8fb6248f44b37dc7d26fe3c00 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Cache/Json/CacheEntry.cs b/Runtime/Core/Cache/Json/CacheEntry.cs new file mode 100644 index 0000000..3edc862 --- /dev/null +++ b/Runtime/Core/Cache/Json/CacheEntry.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using Newtonsoft.Json; + +namespace PatchManager.Core.Cache.Json +{ + /// + /// Represents an entry in the cache for a specific asset label. + /// + [JsonObject(MemberSerialization.OptIn)] + public sealed class CacheEntry + { + /// + /// Label of the asset(s). + /// + [JsonProperty("label", Required = Required.Always)] + public string Label { get; internal set; } + + /// + /// Filename of the archive containing the asset(s). + /// + [JsonProperty("archive", Required = Required.Always)] + public string ArchiveFilename { get; internal set; } + + /// + /// List of all assets in the archive. + /// + [JsonProperty("assets", Required = Required.Always)] + public List Assets { get; internal set; } + } +} \ No newline at end of file diff --git a/Runtime/Core/Cache/Json/CacheEntry.cs.meta b/Runtime/Core/Cache/Json/CacheEntry.cs.meta new file mode 100644 index 0000000..9d09d68 --- /dev/null +++ b/Runtime/Core/Cache/Json/CacheEntry.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bfacc38c9b4aae84393239fccb3bf4dc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Cache/Json/Inventory.cs b/Runtime/Core/Cache/Json/Inventory.cs new file mode 100644 index 0000000..828c99b --- /dev/null +++ b/Runtime/Core/Cache/Json/Inventory.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Newtonsoft.Json; +using PatchManager.Shared; +using UniLinq; + +namespace PatchManager.Core.Cache.Json +{ + /// + /// Serves as a catalog of all patched labels and their respective archives. + /// + [JsonObject(MemberSerialization.OptIn)] + public sealed class Inventory + { + /// + /// Dictionary of all patched labels and their respective archives and assets. + /// + [JsonProperty("cache", Required = Required.Always)] + public Dictionary CacheEntries { get; internal set; } + + /// + /// Checksum hash of the patch_hashes field. + /// + [JsonProperty("checksum", Required = Required.Always)] + public string Checksum { get; internal set; } + + /// + /// Dictionary of all patches and their hashes. + /// + [JsonProperty("patch_hashes", Required = Required.Always)] + public PatchHashes Patches { get; internal set; } + + /// + /// Get a by its label. + /// + /// Asset label to get the entry for. + /// A pair of asset label and instance of if found, otherwise null. + public KeyValuePair GetByLabel(string label) + { + return CacheEntries.FirstOrDefault( + entry => entry.Key == label + ); + } + + /// + /// Get a by its archive's name. + /// + /// Archive filename to get the entry for. + /// A pair of asset label and instance of if found, otherwise null. + public KeyValuePair GetByArchive(string archiveFilename) + { + return CacheEntries.FirstOrDefault( + entry => entry.Value.ArchiveFilename == archiveFilename + ); + } + + internal static Inventory Create() + { + return new Inventory + { + CacheEntries = new Dictionary() + }; + } + + internal static Inventory Load(string path) + { + CacheManager.CreateCacheFolderIfNotExists(); + if (!File.Exists(path)) + { + Logging.LogDebug($"Inventory file does not exist, creating new inventory."); + return Create(); + } + + try + { + var inventoryText = File.ReadAllText(path); + var inventory = JsonConvert.DeserializeObject(inventoryText); + Logging.LogDebug("Inventory file loaded successfully."); + return inventory; + } + catch (Exception e) + { + Logging.LogError($"Inventory file was corrupted: {e.Message}"); + return Create(); + } + } + + internal void Save(string path) + { + CacheManager.CreateCacheFolderIfNotExists(); + var inventoryText = JsonConvert.SerializeObject(this, Formatting.Indented); + File.WriteAllText(path, inventoryText); + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Cache/Json/Inventory.cs.meta b/Runtime/Core/Cache/Json/Inventory.cs.meta new file mode 100644 index 0000000..cda124d --- /dev/null +++ b/Runtime/Core/Cache/Json/Inventory.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27a7dfbe6c8138a4f88d71e1389f3e78 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Cache/Json/PatchHashes.cs b/Runtime/Core/Cache/Json/PatchHashes.cs new file mode 100644 index 0000000..51395c0 --- /dev/null +++ b/Runtime/Core/Cache/Json/PatchHashes.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using PatchManager.Core.Utility; + +namespace PatchManager.Core.Cache.Json +{ + /// + /// Contains hashes of the cache. + /// + [JsonObject(MemberSerialization.OptIn)] + public sealed class PatchHashes + { + /// + /// KSP 2 version for which the cache was generated. + /// + [JsonProperty("ksp2_version", Required = Required.Always)] + public string Ksp2Version { get; internal set; } + + /// + /// PatchManager version for which the cache was generated. + /// + [JsonProperty("patch_manager_version", Required = Required.Always)] + public string PatchManagerVersion { get; internal set; } + + /// + /// Dictionary of all patches and their hashes. + /// + [JsonProperty("patches", Required = Required.Always)] + public Dictionary Patches { get; internal set; } + + /// + /// Create a default instance of with current KSP 2 and Patch Manager versions. + /// + /// Default instance of + public static PatchHashes CreateDefault() + { + return new PatchHashes + { + Ksp2Version = Versions.Ksp2Version, + PatchManagerVersion = Versions.PatchManagerVersion, + Patches = new Dictionary() + }; + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Cache/Json/PatchHashes.cs.meta b/Runtime/Core/Cache/Json/PatchHashes.cs.meta new file mode 100644 index 0000000..7b2b1a7 --- /dev/null +++ b/Runtime/Core/Cache/Json/PatchHashes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 149acccd7a573894982a52e772a6ec30 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/CoreModule.cs b/Runtime/Core/CoreModule.cs new file mode 100644 index 0000000..1033cf6 --- /dev/null +++ b/Runtime/Core/CoreModule.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using System.IO; +using JetBrains.Annotations; +using KSP.Game; +using Newtonsoft.Json; +using PatchManager.Core.Assets; +using PatchManager.Core.Cache; +using PatchManager.SassyPatching.Execution; +using PatchManager.Shared; +using PatchManager.Shared.Modules; +using ReduxLib.Configuration; +using SpaceWarp.API.Mods.JSON; +using UniLinq; +using Unity.VisualScripting; +using UnityEngine; +using UnityEngine.AddressableAssets; +using UnityEngine.UIElements; +using FlowAction = PatchManager.Core.Flow.FlowAction; + +namespace PatchManager.Core +{ + /// + /// Core module for PatchManager. + /// + [UsedImplicitly] + public class CoreModule : BaseModule + { + private const string PATCH_LABEL = "redux_patches"; + private const string REDUX_MOD_ID = "Redux"; + + private ConfigValue _shouldAlwaysInvalidate; + + private bool _wasCacheInvalidated; + + private static bool ShouldLoad(IEnumerable disabled, string modInfoLocation) + { + if (!File.Exists(modInfoLocation)) + return false; + try + { + var metadata = JsonConvert.DeserializeObject(File.ReadAllText(modInfoLocation)); + return metadata.ModID == null || disabled.All(x => x != metadata.ModID); + } + catch + { + return false; + } + } + + private static bool NoSwinfo(DirectoryInfo directory, DirectoryInfo gameRoot) + { + while (directory != null && directory != gameRoot) + { + if (directory.GetFiles().Any(x => x.Name == "swinfo.json")) + return false; + directory = directory.Parent; + } + + return true; + } + + /// + /// Reads all patch files. + /// + public override void Init() + { + if (_shouldAlwaysInvalidate.Value || SpaceWarp.API.Mods.PluginList.ModListChangedSinceLastRun) + { + CacheManager.CreateCacheFolderIfNotExists(); + CacheManager.InvalidateCache(); + } + + var isValid = PatchingManager.InvalidateCacheIfNeeded(); + + if (!isValid) + { + _wasCacheInvalidated = true; + SpaceWarp.API.Loading.Loading.GeneralLoadingActions.Insert(0, + () => new FlowAction("Patch Manager: Creating New Assets", PatchingManager.CreateNewAssets)); + SpaceWarp.API.Loading.Loading.GeneralLoadingActions.Insert(1, + () => new FlowAction("Patch Manager: Rebuilding Cache", PatchingManager.RebuildAllCache)); + SpaceWarp.API.Loading.Loading.GeneralLoadingActions.Insert(2, + () => new FlowAction("Patch Manager: Registering Resource Locator", RegisterResourceLocator)); + } + else + { + SpaceWarp.API.Loading.Loading.GeneralLoadingActions.Insert(0, + () => new FlowAction("Patch Manager: Registering Resource Locator", RegisterResourceLocator)); + } + } + + /// + public override void PreLoad() + { + // Go here instead so that the static constructor recognizes everything + var disabledPlugins = File.ReadAllText(SpaceWarp.API.CommonPaths.DisabledPlugins) + .Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList(); + + var modFolders = Directory.GetDirectories(SpaceWarp.API.CommonPaths.ModsFolder, "*", SearchOption.AllDirectories) + .Where(dir => ShouldLoad(disabledPlugins, Path.Combine(dir, "swinfo.json"))) + .Select(x => ( + Folder: x, + Info: JsonConvert.DeserializeObject(File.ReadAllText(Path.Combine(x, "swinfo.json"))) + )) + .ToList(); + + var gameRoot = new DirectoryInfo("."); + + var standalonePatches = Directory.EnumerateFiles( + SpaceWarp.API.CommonPaths.ModsFolder, + "*.patch", + SearchOption.AllDirectories + ) + .Where(x => NoSwinfo(new FileInfo(x).Directory, gameRoot)) + .Select(x => new FileInfo(x)) + .ToList(); + + + PatchingManager.GenerateUniverse(standalonePatches.Select(x => + x.Directory!.FullName + .MakeRelativePathTo(gameRoot.FullName) + .Replace("\\", "-") + ).ToHashSet()); + + var handle = GameManager.Instance.Assets.LoadAssetsAsync(PATCH_LABEL, asset => + { + PatchingManager.ImportAssetPatch(asset, REDUX_MOD_ID); + }); + handle.Completed += _ => + { + Addressables.Release(handle); + }; + handle.WaitForCompletion(); + + foreach (var modFolder in modFolders) + { + Logging.LogInfo($"Loading patchers from {modFolder.Folder}"); + // var modName = Path.GetDirectoryName(modFolder); + PatchingManager.ImportModPatches(modFolder.Info.ModID, modFolder.Folder); + } + + foreach (var standalonePatch in standalonePatches) + { + PatchingManager.ImportSinglePatch(standalonePatch); + } + + PatchingManager.RegisterPatches(); + } + + /// + /// Registers the provider and locator for cached assets. + /// + private void RegisterResourceLocator(Action resolve, Action reject) + { + Addressables.ResourceManager.ResourceProviders.Add(new ArchiveResourceProvider()); + Locators.Register(new ArchiveResourceLocator()); + resolve(); + } + + /// + public override VisualElement GetDetails() + { + var foldout = new Foldout + { + text = "PatchManager.Core", + style = + { + display = DisplayStyle.Flex + }, + visible = true + }; + var text = new TextElement(); + text.text += $"Amount of loaded patchers: {PatchingManager.Patchers.Count}\n"; + text.text += $"Amount of loaded generators: {PatchingManager.Generators.Count}\n"; + text.text += $"Amount of loaded libraries: {PatchingManager.Universe.AllLibraries.Count}\n"; + if (_wasCacheInvalidated) + { + text.text += $"Total amount of patches: {PatchingManager.TotalPatchCount}\n"; + } + else + { + text.text += "Total amount of patches: Unknown (loaded from cache)\n"; + } + text.text += $"Total amount of errors: {PatchingManager.TotalErrorCount}\n"; + + text.text += "Patched labels:"; + foreach (var label in PatchingManager.Universe.LoadedLabels) + { + text.text += $"\n- {label}"; + } + + text.visible = true; + text.style.display = DisplayStyle.Flex; + foldout.Add(text); + + return foldout; + } + + /// + public override void BindConfiguration(IConfigFile modConfiguration) + { + _shouldAlwaysInvalidate = new(modConfiguration.Bind("Advanced", "Always Invalidate Patch Manager Cache", false, + "Should patch manager always invalidate its cache upon load")); + } + + /// + /// This is the current universe that patch manager is using (used for interop reasons) + /// + [PublicAPI] + public static Universe CurrentUniverse => PatchingManager.Universe; + } +} \ No newline at end of file diff --git a/Runtime/Core/CoreModule.cs.meta b/Runtime/Core/CoreModule.cs.meta new file mode 100644 index 0000000..4ecca6b --- /dev/null +++ b/Runtime/Core/CoreModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 13e32996b99a9bb448d368e82751de01 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Flow.meta b/Runtime/Core/Flow.meta new file mode 100644 index 0000000..a3eb6a6 --- /dev/null +++ b/Runtime/Core/Flow.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b4fd5af28c064b041938d23da96235f7 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Flow/FlowAction.cs b/Runtime/Core/Flow/FlowAction.cs new file mode 100644 index 0000000..afa7033 --- /dev/null +++ b/Runtime/Core/Flow/FlowAction.cs @@ -0,0 +1,36 @@ +using System; +using ReduxLib.GameInterfaces; + +namespace PatchManager.Core.Flow +{ + /// + /// Represents a general action to be executed during game loading. + /// + public class FlowAction : IFlowAction + { + private readonly Action> _doAction; + + /// + /// Creates a new instance of . + /// + /// + /// + public FlowAction(string name, Action> doAction) + { + Name = name; + Description = name; + _doAction = doAction; + } + + /// + public string Name { get; } + + public string Description { get; } + + /// + public void DoAction(Action resolve, Action reject) + { + _doAction(resolve, reject); + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Flow/FlowAction.cs.meta b/Runtime/Core/Flow/FlowAction.cs.meta new file mode 100644 index 0000000..5640e55 --- /dev/null +++ b/Runtime/Core/Flow/FlowAction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c385a498f22b0b4d9bb3deda4b7ae95 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Flow/FlowManager.cs b/Runtime/Core/Flow/FlowManager.cs new file mode 100644 index 0000000..58c09c0 --- /dev/null +++ b/Runtime/Core/Flow/FlowManager.cs @@ -0,0 +1,52 @@ +using System.Collections.Generic; +using KSP.Game.Flow; +using PatchManager.Shared; +using ReduxLib.GameInterfaces; +using SpaceWarp.API.Loading; + +namespace PatchManager.Core.Flow +{ + /// + /// Manages injection of game loading flow actions. + /// + public static class FlowManager + { + private static readonly List Actions = new(); + + private static readonly Dictionary ActionsAfter = new(); + + /// + /// Registers an action to be executed at the end of game loading. + /// + /// Action to be executed. + public static void RegisterAction(IFlowAction action) + { + Actions.Add(action); + } + + /// + /// Registers an action to be executed during game loading. + /// + /// Action to be executed. + /// Action name to insert the new action after, null to insert at the beginning. + public static void RegisterActionAfter(IFlowAction action, string after) + { + ActionsAfter.Add(action, after); + } + + internal static void AddActionsToFlow(SequentialFlow loadingFlow) + { + foreach (var action in Actions) + { + loadingFlow.AddAction(new GenericFlowAction(action.Name, action.DoAction)); + Logging.LogDebug($"Registering flow action at the end: \"{action.Name}\""); + } + + foreach (var (action, after) in ActionsAfter) + { + SaveLoad.AddFlowActionToGameLoadAfter(action, after); + Logging.LogDebug($"Registering flow action \"{action.Name}\" after \"{after}\""); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Flow/FlowManager.cs.meta b/Runtime/Core/Flow/FlowManager.cs.meta new file mode 100644 index 0000000..4815f69 --- /dev/null +++ b/Runtime/Core/Flow/FlowManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 008fe58644316234c92e4a6739824382 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Utility.meta b/Runtime/Core/Utility.meta new file mode 100644 index 0000000..c6df6fd --- /dev/null +++ b/Runtime/Core/Utility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 02b40754847d50a4999a1bb1ae79c958 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Utility/Hash.cs b/Runtime/Core/Utility/Hash.cs new file mode 100644 index 0000000..72ea573 --- /dev/null +++ b/Runtime/Core/Utility/Hash.cs @@ -0,0 +1,55 @@ +using System; +using System.IO; +using System.Security.Cryptography; +using System.Text; +using Newtonsoft.Json; + +namespace PatchManager.Core.Utility +{ + /// + /// Hashing utility class. + /// + public static class Hash + { + private static readonly MD5 Md5 = MD5.Create(); + + /// + /// Gets the MD5 hash of the input string. + /// + /// Input string. + /// MD5 hash of the input string. + public static string FromString(string input) + { + var hash = Md5.ComputeHash(Encoding.UTF8.GetBytes(input)); + return ByteArrayToString(hash); + } + + /// + /// Gets the MD5 hash of the input file. + /// + /// Path to the file. + /// MD5 hash of the input file. + public static string FromFile(string path) + { + var hash = Md5.ComputeHash(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)); + return ByteArrayToString(hash); + } + + /// + /// Gets the MD5 hash of the input JSON-serializable object. + /// + /// JSON-serializable object. + /// MD5 hash of the JSON-serializable object. + public static string FromJsonObject(object input) + { + var json = JsonConvert.SerializeObject(input, Formatting.None); + return FromString(json); + } + + private static string ByteArrayToString(byte[] array) + { + var hashString = BitConverter.ToString(array).Replace("-", ""); + return hashString; + } + } +} \ No newline at end of file diff --git a/Runtime/Core/Utility/Hash.cs.meta b/Runtime/Core/Utility/Hash.cs.meta new file mode 100644 index 0000000..a5b5c55 --- /dev/null +++ b/Runtime/Core/Utility/Hash.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 15e120e4360641247b52d6f056bb2973 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Core/Utility/Versions.cs b/Runtime/Core/Utility/Versions.cs new file mode 100644 index 0000000..e2bde45 --- /dev/null +++ b/Runtime/Core/Utility/Versions.cs @@ -0,0 +1,29 @@ +using System.Reflection; + +namespace PatchManager.Core.Utility +{ + /// + /// Utility class containing versions of KSP 2 and PatchManager. + /// + public static class Versions + { + /// + /// Currently running KSP 2 version. + /// + public static string Ksp2Version + { + get + { + var type = typeof(VersionID); + var field = type.GetField("VERSION_TEXT", BindingFlags.Static | BindingFlags.Public); + var value = field?.GetValue(null) as string; + return value; + } + } + + /// + /// Currently running PatchManager version. + /// + public static string PatchManagerVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString(); + } +} \ No newline at end of file diff --git a/Runtime/Core/Utility/Versions.cs.meta b/Runtime/Core/Utility/Versions.cs.meta new file mode 100644 index 0000000..6602595 --- /dev/null +++ b/Runtime/Core/Utility/Versions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d5dcf32c99a3fd6498eebc5e570f7fd4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Generic.meta b/Runtime/Generic.meta new file mode 100644 index 0000000..3896dbd --- /dev/null +++ b/Runtime/Generic.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ad4ecf00418fe0840899a986d80260af +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Generic/GenericModule.cs b/Runtime/Generic/GenericModule.cs new file mode 100644 index 0000000..22bfbe4 --- /dev/null +++ b/Runtime/Generic/GenericModule.cs @@ -0,0 +1,9 @@ +using PatchManager.Shared.Modules; + +namespace PatchManager.Generic +{ + public class GenericModule : BaseModule + { + + } +} \ No newline at end of file diff --git a/Runtime/Generic/GenericModule.cs.meta b/Runtime/Generic/GenericModule.cs.meta new file mode 100644 index 0000000..1534443 --- /dev/null +++ b/Runtime/Generic/GenericModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e55081d3a915442eb8ec003084557b76 +timeCreated: 1739404342 \ No newline at end of file diff --git a/Runtime/Generic/SassyPatching.meta b/Runtime/Generic/SassyPatching.meta new file mode 100644 index 0000000..76b6391 --- /dev/null +++ b/Runtime/Generic/SassyPatching.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d7e68c3aedf831d44af306be6686331a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Generic/SassyPatching/Rulesets.meta b/Runtime/Generic/SassyPatching/Rulesets.meta new file mode 100644 index 0000000..48cfe00 --- /dev/null +++ b/Runtime/Generic/SassyPatching/Rulesets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 46a99f7316bdd984daed29c96770d544 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Generic/SassyPatching/Rulesets/JsonRuleset.cs b/Runtime/Generic/SassyPatching/Rulesets/JsonRuleset.cs new file mode 100644 index 0000000..86098ae --- /dev/null +++ b/Runtime/Generic/SassyPatching/Rulesets/JsonRuleset.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; +using PatchManager.SassyPatching.Selectables; + +namespace PatchManager.Generic.SassyPatching.Rulesets +{ + /// + /// This is a generic json patching ruleset + /// + [PatcherRuleset("json")] + public class JsonRuleset : IPatcherRuleSet + { + /// + public bool Matches(string label) + { + return true; + } + + /// + public ISelectable ConvertToSelectable(string type, string name, string jsonData) + { + return new JTokenSelectable(() => { }, JToken.Parse(jsonData), name, type); + } + + /// + public INewAsset CreateNew(List dataValues) + { + var label = dataValues[0].String; + var name = dataValues[1].String; + return new NewGenericAsset(label, name, new JTokenSelectable(() => { }, new JObject(), name, label)); + } + } +} \ No newline at end of file diff --git a/Runtime/Generic/SassyPatching/Rulesets/JsonRuleset.cs.meta b/Runtime/Generic/SassyPatching/Rulesets/JsonRuleset.cs.meta new file mode 100644 index 0000000..2603a29 --- /dev/null +++ b/Runtime/Generic/SassyPatching/Rulesets/JsonRuleset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4f73779c543bd394bac28e903bdf0ed4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions.meta b/Runtime/Missions.meta new file mode 100644 index 0000000..db47307 --- /dev/null +++ b/Runtime/Missions.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d87536dafb254407910d933e885093cd +timeCreated: 1739386689 \ No newline at end of file diff --git a/Runtime/Missions/Builtins.meta b/Runtime/Missions/Builtins.meta new file mode 100644 index 0000000..c9d4b39 --- /dev/null +++ b/Runtime/Missions/Builtins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ecc7b0831443ce44aab2ddca806143a1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Builtins/MissionsBuiltins.cs b/Runtime/Missions/Builtins/MissionsBuiltins.cs new file mode 100644 index 0000000..11896cd --- /dev/null +++ b/Runtime/Missions/Builtins/MissionsBuiltins.cs @@ -0,0 +1,31 @@ +using JetBrains.Annotations; +using PatchManager.SassyPatching.Attributes; + +namespace PatchManager.Missions.Builtins +{ + /// + /// Builtins for missions. + /// + [SassyLibrary("builtin","missions")] + [UsedImplicitly] + public class MissionsBuiltins + { + /// + /// Gets the assembly-qualified type name of a property watcher. + /// + /// The name of the property watcher. + /// The assembly-qualified type name of the property watcher. + [SassyMethod("get-property-watcher"), UsedImplicitly] + public static string GetPropertyWatcher([SassyName("property-watcher-name")] string propertyWatcherName) => + MissionsTypes.PropertyWatchers[propertyWatcherName].AssemblyQualifiedName!; + + /// + /// Gets the assembly-qualified type name of a message. + /// + /// The name of the message. + /// The assembly-qualified type name of the message. + [SassyMethod("get-message"), UsedImplicitly] + public static string GetMessage([SassyName("message-name")] string messageName) => + MissionsTypes.Messages[messageName].AssemblyQualifiedName!; + } +} \ No newline at end of file diff --git a/Runtime/Missions/Builtins/MissionsBuiltins.cs.meta b/Runtime/Missions/Builtins/MissionsBuiltins.cs.meta new file mode 100644 index 0000000..aff208f --- /dev/null +++ b/Runtime/Missions/Builtins/MissionsBuiltins.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a41288ebe4ed77248bc76edbca66d9e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/MissionsModule.cs b/Runtime/Missions/MissionsModule.cs new file mode 100644 index 0000000..e1f6fcd --- /dev/null +++ b/Runtime/Missions/MissionsModule.cs @@ -0,0 +1,9 @@ +using PatchManager.Shared.Modules; + +namespace PatchManager.Missions +{ + public class MissionsModule : BaseModule + { + + } +} \ No newline at end of file diff --git a/Runtime/Missions/MissionsModule.cs.meta b/Runtime/Missions/MissionsModule.cs.meta new file mode 100644 index 0000000..ae7e85a --- /dev/null +++ b/Runtime/Missions/MissionsModule.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 98566c5e1f144908a590fa78d9364794 +timeCreated: 1739404368 \ No newline at end of file diff --git a/Runtime/Missions/MissionsTypes.cs b/Runtime/Missions/MissionsTypes.cs new file mode 100644 index 0000000..016de79 --- /dev/null +++ b/Runtime/Missions/MissionsTypes.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using KSP.Game.Missions; +using KSP.Messages; +using KSP.Messages.PropertyWatchers; +using UniLinq; + +namespace PatchManager.Missions +{ + /// + /// This class is used to get all the types of the missions. + /// + public static class MissionsTypes + { + /// + /// Dictionary of all the conditions. + /// + public static readonly Dictionary Conditions = new(); + /// + /// Dictionary of all the actions. + /// + public static readonly Dictionary Actions = new(); + /// + /// Dictionary of all the messages. + /// + public static readonly Dictionary Messages = new(); + /// + /// Dictionary of all the property watchers. + /// + public static readonly Dictionary PropertyWatchers = new(); + + static MissionsTypes() + { + foreach (var type in AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()).Where(t => !t.IsAbstract)) + { + if (type.IsSubclassOf(typeof(Condition))) + { + Conditions.Add(type.Name,type); + } + + if (typeof(IMissionAction).IsAssignableFrom(type)) + { + Actions.Add(type.Name, type); + } + + if (type.IsSubclassOf(typeof(MessageCenterMessage))) + { + Messages.Add(type.Name, type); + } + + if (type.IsSubclassOf(typeof(PropertyWatcher))) + { + PropertyWatchers.Add(type.Name, type); + } + } + } + } +} \ No newline at end of file diff --git a/Runtime/Missions/MissionsTypes.cs.meta b/Runtime/Missions/MissionsTypes.cs.meta new file mode 100644 index 0000000..4977ce5 --- /dev/null +++ b/Runtime/Missions/MissionsTypes.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6f11288ff651c694f82c177884e8bca1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Modifiables.meta b/Runtime/Missions/Modifiables.meta new file mode 100644 index 0000000..9aa1c6e --- /dev/null +++ b/Runtime/Missions/Modifiables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 09e739a29b1907f4d957463b50672f5f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Modifiables/MissionModifiable.cs b/Runtime/Missions/Modifiables/MissionModifiable.cs new file mode 100644 index 0000000..44676f9 --- /dev/null +++ b/Runtime/Missions/Modifiables/MissionModifiable.cs @@ -0,0 +1,40 @@ +using PatchManager.Missions.Selectables; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Modifiables; + +namespace PatchManager.Missions.Modifiables +{ + /// + /// Modifiable for . This is used to modify the mission object. + /// + public class MissionModifiable : JTokenModifiable + { + /// + /// The that this modifiable is for. + /// + private readonly MissionSelectable _missionSelectable; + + /// + /// Creates a new for the given . + /// + /// The to create the modifiable for. + public MissionModifiable(MissionSelectable selectable) : base(selectable.MissionObject, selectable.SetModified) + { + _missionSelectable = selectable; + } + + /// + /// Sets the to be deleted if the is a deletion. + /// + /// The to set. + public override void Set(DataValue dataValue) + { + if (dataValue.IsDeletion) + { + _missionSelectable.SetDeleted(); + return; + } + base.Set(dataValue); + } + } +} \ No newline at end of file diff --git a/Runtime/Missions/Modifiables/MissionModifiable.cs.meta b/Runtime/Missions/Modifiables/MissionModifiable.cs.meta new file mode 100644 index 0000000..fdfadd8 --- /dev/null +++ b/Runtime/Missions/Modifiables/MissionModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6dcd1b0376f2bbc438435ab4dffe75d3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Rulesets.meta b/Runtime/Missions/Rulesets.meta new file mode 100644 index 0000000..9a1e6c3 --- /dev/null +++ b/Runtime/Missions/Rulesets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5e5925c61f895d9439d5b15ea5c090e3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Rulesets/MissionRuleset.cs b/Runtime/Missions/Rulesets/MissionRuleset.cs new file mode 100644 index 0000000..faa91d6 --- /dev/null +++ b/Runtime/Missions/Rulesets/MissionRuleset.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using KSP.Game.Missions.Definitions; +using Newtonsoft.Json.Linq; +using PatchManager.Missions.Selectables; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; + +namespace PatchManager.Missions.Rulesets +{ + /// + /// Ruleset for the missions patcher. + /// + [PatcherRuleset("missions","missions")] + public class MissionRuleset : IPatcherRuleSet + { + /// + public bool Matches(string label) => label == "missions"; + + /// + public ISelectable ConvertToSelectable(string type, string name, string jsonData) => + new MissionSelectable(JObject.Parse(jsonData)); + + /// + public INewAsset CreateNew(List dataValues) + { + var missionDataObject = new MissionData + { + ID = dataValues[0].String + }; + + return new NewGenericAsset("missions", dataValues[0].String, + new MissionSelectable(JObject.FromObject(missionDataObject))); + } + } +} \ No newline at end of file diff --git a/Runtime/Missions/Rulesets/MissionRuleset.cs.meta b/Runtime/Missions/Rulesets/MissionRuleset.cs.meta new file mode 100644 index 0000000..cb90e1f --- /dev/null +++ b/Runtime/Missions/Rulesets/MissionRuleset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f35302b0a7d113e4d8301b4751e220b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Selectables.meta b/Runtime/Missions/Selectables.meta new file mode 100644 index 0000000..c03eee5 --- /dev/null +++ b/Runtime/Missions/Selectables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 319ed6f60c1ee7748be6a2e580d41ae3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Selectables/ActionsSelectable.cs b/Runtime/Missions/Selectables/ActionsSelectable.cs new file mode 100644 index 0000000..5ff7cf5 --- /dev/null +++ b/Runtime/Missions/Selectables/ActionsSelectable.cs @@ -0,0 +1,132 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Modifiables; +using PatchManager.SassyPatching.Selectables; + +namespace PatchManager.Missions.Selectables +{ + /// + /// Selectable for the actions array of a mission. + /// + public sealed class ActionsSelectable : BaseSelectable + { + /// + /// The mission selectable that this actions selectable belongs to. + /// + public MissionSelectable Selectable; + + /// + /// The actions array. + /// + public JArray Actions; + + private static string TrimTypeName(string typeName) + { + var comma = typeName.IndexOf(','); + if (comma != -1) + { + typeName = typeName[..comma]; + } + + var period = typeName.LastIndexOf('.'); + if (period != -1) + { + typeName = typeName[(period + 1)..]; + } + + return typeName; + } + + /// + /// Creates a new actions selectable. + /// + /// Mission selectable that this actions selectable belongs to. + /// Actions array. + public ActionsSelectable(MissionSelectable selectable, JArray actions) + { + Selectable = selectable; + Actions = actions; + Children = new List(); + Classes = new List(); + foreach (var action in actions) + { + var obj = (JObject)action; + var type = obj["$type"]!.Value()!; + var trimmedType = TrimTypeName(type); + Classes.Add(trimmedType); + Children.Add(new JTokenSelectable( + Selectable.SetModified, + obj, + token => TrimTypeName(((JObject)token)!.Value()!), + trimmedType + )); + } + } + + /// + public override List Children { get; } + + /// + public override string Name => "actions"; + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + foreach (var action in Actions) + { + var obj = (JObject)action; + var type = obj["$type"]!.Value()!; + var trimmedType = TrimTypeName(type); + if (trimmedType != @class) continue; + classValue = DataValue.FromJToken(action); + return true; + } + + classValue = DataValue.Null; + return false; + } + + /// + public override bool IsSameAs(ISelectable other) => + other is ActionsSelectable actionsSelectable && actionsSelectable.Actions == Actions; + + /// + public override IModifiable OpenModification() => new JTokenModifiable(Actions, Selectable.SetModified); + + /// + public override ISelectable AddElement(string elementType) + { + var actualType = MissionsTypes.Actions[elementType]; + var elementObject = new JObject() + { + ["$type"] = actualType.AssemblyQualifiedName + }; + foreach (var (key, value) in JObject.FromObject(Activator.CreateInstance(actualType))) + { + elementObject[key] = value; + } + + var selectable = new JTokenSelectable(Selectable.SetModified, elementObject, + token => TrimTypeName(((JObject)token)!.Value()!), elementType); + Children.Add(selectable); + Classes.Add(elementType); + Actions.Add(elementObject); + return selectable; + } + + /// + public override string Serialize() => Actions.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(Actions); + + /// + public override string ElementType => "actions"; + } +} \ No newline at end of file diff --git a/Runtime/Missions/Selectables/ActionsSelectable.cs.meta b/Runtime/Missions/Selectables/ActionsSelectable.cs.meta new file mode 100644 index 0000000..12e85f2 --- /dev/null +++ b/Runtime/Missions/Selectables/ActionsSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b06ba582f155b594093f3f43ab7ca758 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Selectables/ConditionSetSelectable.cs b/Runtime/Missions/Selectables/ConditionSetSelectable.cs new file mode 100644 index 0000000..3ea1497 --- /dev/null +++ b/Runtime/Missions/Selectables/ConditionSetSelectable.cs @@ -0,0 +1,140 @@ +using System; +using System.Collections.Generic; +using KSP.Game.Missions; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Modifiables; +using PatchManager.SassyPatching.Selectables; + +namespace PatchManager.Missions.Selectables +{ + /// + /// Selectable for the condition set of a mission. + /// + public sealed class ConditionSetSelectable : BaseSelectable + { + /// + /// The mission selectable that this condition set is a child of + /// + public MissionSelectable MissionSelectable; + + /// + /// The condition set that this selectable represents + /// + public JObject ConditionSet; + + /// + /// The children of this condition set + /// + private JArray _children; + + /// + /// Create a new condition set selectable + /// + /// Mission selectable that this condition set is a child of + /// The condition set that this selectable represents + public ConditionSetSelectable(MissionSelectable missionSelectable, JObject conditionSet) + { + MissionSelectable = missionSelectable; + ConditionSet = conditionSet; + _children = (JArray)conditionSet["Children"]!; + Children = new List(); + Classes = new List + { + "ConditionType", + "ConditionMode" + }; + // We aren't going to add the condition type as a child, it will still be editable tho + foreach (var child in _children) + { + var condition = (JObject)child; + var type = condition["ConditionType"]!.Value()!; + Classes.Add(type); + if (type == "ConditionSet") + { + Children.Add(new ConditionSetSelectable(missionSelectable, condition)); + } + else + { + Children.Add(new JTokenSelectable( + MissionSelectable.SetModified, + condition, + token => ((JObject)token)["ConditionType"]!.Value()!, + type + )); + } + } + } + + /// + public override List Children { get; } + + /// + public override string Name => "ConditionSet"; + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + foreach (var child in _children) + { + var condition = (JObject)child; + var type = condition["ConditionType"]!.Value()!; + if (type != @class) + continue; + classValue = DataValue.FromJToken(child); + } + + classValue = DataValue.Null; + return false; + } + + /// + public override bool IsSameAs(ISelectable other) => other is ConditionSetSelectable conditionSetSelectable && + conditionSetSelectable.ConditionSet == ConditionSet; + + /// + public override IModifiable OpenModification() => new JTokenModifiable(ConditionSet, MissionSelectable.SetModified); + + /// + public override ISelectable AddElement(string elementType) + { + var conditionType = MissionsTypes.Conditions[elementType]; + var conditionObject = new JObject() + { + ["$type"] = conditionType.AssemblyQualifiedName + }; + foreach (var (key, value) in JObject.FromObject(Activator.CreateInstance(conditionType))) + { + conditionObject[key] = value; + } + + _children.Add(conditionObject); + if (conditionType == typeof(ConditionSet)) + { + var selectable = new ConditionSetSelectable(MissionSelectable, conditionObject); + Children.Add(selectable); + return selectable; + } + else + { + var selectable = new JTokenSelectable(MissionSelectable.SetModified, conditionObject, + "scriptableCondition", "scriptableCondition"); + Children.Add(selectable); + return selectable; + } + } + + /// + public override string Serialize() => ConditionSet.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(ConditionSet); + + /// + public override string ElementType => "ConditionSet"; + } +} \ No newline at end of file diff --git a/Runtime/Missions/Selectables/ConditionSetSelectable.cs.meta b/Runtime/Missions/Selectables/ConditionSetSelectable.cs.meta new file mode 100644 index 0000000..bc320fe --- /dev/null +++ b/Runtime/Missions/Selectables/ConditionSetSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 46ee6c1e9a098e445a5f90678ca0d396 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Selectables/ContentBranchSelectable.cs b/Runtime/Missions/Selectables/ContentBranchSelectable.cs new file mode 100644 index 0000000..03bbcd5 --- /dev/null +++ b/Runtime/Missions/Selectables/ContentBranchSelectable.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Modifiables; + +namespace PatchManager.Missions.Selectables +{ + /// + /// A selectable for a content branch. + /// + public sealed class ContentBranchSelectable : BaseSelectable + { + /// + /// The mission selectable that this content branch belongs to. + /// + public MissionSelectable Selectable; + + /// + /// The content branch that this selectable represents. + /// + public JObject ContentBranch; + + /// + /// The actions selectable that this content branch contains. + /// + private ActionsSelectable _actionsSelectable; + + /// + /// Creates a new content branch selectable. + /// + /// Mission selectable that this content branch belongs to. + /// Content branch that this selectable represents. + public ContentBranchSelectable(MissionSelectable selectable, JObject contentBranch) + { + Selectable = selectable; + ContentBranch = contentBranch; + Classes = new List { "actions" }; + Children = new List(); + _actionsSelectable = new ActionsSelectable(selectable, (JArray)contentBranch["actions"]!); + Children.Add(_actionsSelectable); + Classes.AddRange(_actionsSelectable.Classes); + Children.AddRange(_actionsSelectable.Children); + } + + /// + public override List Children { get; } + + /// + public override string Name => ContentBranch["ID"]!.Value()!; + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) => + _actionsSelectable.MatchesClass(@class, out classValue); + + /// + public override bool IsSameAs(ISelectable other) => other is ContentBranchSelectable contentBranchSelectable && + contentBranchSelectable.ContentBranch == ContentBranch; + + /// + public override IModifiable OpenModification() => new JTokenModifiable(ContentBranch, Selectable.SetModified); + + /// + public override ISelectable AddElement(string elementType) + { + var result = _actionsSelectable.AddElement(elementType); + Children.Add(result); + Classes.Add(elementType); + return result; + } + + /// + public override string Serialize() => ContentBranch.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(ContentBranch); + + /// + public override string ElementType => ContentBranch["ID"]!.Value()!; + } +} \ No newline at end of file diff --git a/Runtime/Missions/Selectables/ContentBranchSelectable.cs.meta b/Runtime/Missions/Selectables/ContentBranchSelectable.cs.meta new file mode 100644 index 0000000..9faca89 --- /dev/null +++ b/Runtime/Missions/Selectables/ContentBranchSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e57957c03f769e14e9262e5711594e75 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Selectables/ContentBranchesSelectable.cs b/Runtime/Missions/Selectables/ContentBranchesSelectable.cs new file mode 100644 index 0000000..fa29d19 --- /dev/null +++ b/Runtime/Missions/Selectables/ContentBranchesSelectable.cs @@ -0,0 +1,102 @@ +using System.Collections.Generic; +using KSP.Game.Missions; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Modifiables; + +namespace PatchManager.Missions.Selectables +{ + /// + /// Selectable for the ContentBranches of a Mission + /// + public sealed class ContentBranchesSelectable : BaseSelectable + { + /// + /// The MissionSelectable this ContentBranchesSelectable belongs to + /// + public MissionSelectable Selectable; + + /// + /// The ContentBranches of the Mission + /// + public JArray ContentBranches; + + /// + /// Create a new ContentBranchesSelectable + /// + /// Mission selectable this ContentBranchesSelectable belongs to + /// Content branches of the mission + public ContentBranchesSelectable(MissionSelectable selectable, JArray contentBranches) + { + Selectable = selectable; + ContentBranches = contentBranches; + Children = new List(); + Classes = new List(); + foreach (var child in ContentBranches) + { + var obj = (JObject)child; + var id = obj["ID"]!.Value()!; + Classes.Add(id); + Children.Add(new ContentBranchSelectable(selectable,obj)); + } + } + + /// + public override List Children { get; } + + /// + public override string Name => "ContentBranches"; + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + foreach (var child in ContentBranches) + { + var obj = (JObject)child; + var id = obj["ID"]!.Value()!; + if (id != @class) + continue; + classValue = DataValue.FromJToken(obj); + return true; + } + + classValue = DataValue.Null; + return false; + } + + /// + public override bool IsSameAs(ISelectable other) => other is ContentBranchesSelectable contentBranchesSelectable && + contentBranchesSelectable.ContentBranches == ContentBranches; + + /// + public override IModifiable OpenModification() => new JTokenModifiable(ContentBranches, Selectable.SetModified); + + /// + public override ISelectable AddElement(string elementType) + { + var branch = new MissionContentBranch + { + ID = elementType + }; + var obj = JObject.FromObject(branch); + var selectable = new ContentBranchSelectable(Selectable, obj); + Children.Add(selectable); + Classes.Add(elementType); + ContentBranches.Add(obj); + return selectable; + } + + /// + public override string Serialize() => ContentBranches.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(ContentBranches); + + /// + public override string ElementType => "ContentBranches"; + } +} \ No newline at end of file diff --git a/Runtime/Missions/Selectables/ContentBranchesSelectable.cs.meta b/Runtime/Missions/Selectables/ContentBranchesSelectable.cs.meta new file mode 100644 index 0000000..f67717e --- /dev/null +++ b/Runtime/Missions/Selectables/ContentBranchesSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3cef19219ab97f94c85379a2af2c7d94 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Selectables/MissionRewardSelectable.cs b/Runtime/Missions/Selectables/MissionRewardSelectable.cs new file mode 100644 index 0000000..9187678 --- /dev/null +++ b/Runtime/Missions/Selectables/MissionRewardSelectable.cs @@ -0,0 +1,113 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Modifiables; +using PatchManager.SassyPatching.Selectables; + +namespace PatchManager.Missions.Selectables +{ + /// + /// A selectable for a mission reward. + /// + public sealed class MissionRewardSelectable : BaseSelectable + { + /// + /// The mission selectable this reward belongs to. + /// + public MissionSelectable MissionSelectable; + + /// + /// The mission reward. + /// + public JObject MissionReward; + + /// + /// The mission reward definitions. + /// + private JArray _missionRewardDefinitions; + + /// + /// Creates a new mission reward selectable. + /// + /// Mission selectable this reward belongs to. + /// Mission reward. + public MissionRewardSelectable(MissionSelectable missionSelectable, JObject missionReward) + { + MissionSelectable = missionSelectable; + MissionReward = missionReward; + _missionRewardDefinitions = (JArray)missionReward["MissionRewardDefinitions"]!; + Classes = new List(); + Children = new List(); + foreach (var child in _missionRewardDefinitions) + { + var obj = (JObject)child; + var name = obj["MissionRewardType"]!.Value()!; + Classes.Add(name); + Children.Add(new JTokenSelectable(MissionSelectable.SetModified, child, + token => ((JObject)token)["MissionRewardType"]!.Value(), name)); + } + } + + /// + public override List Children { get; } + + /// + public override string Name => "MissionReward"; + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + foreach (var child in _missionRewardDefinitions) + { + var obj = (JObject)child; + var name = obj["MissionRewardType"]!.Value()!; + if (name != @class) + { + continue; + } + + classValue = DataValue.FromJToken(obj); + return true; + } + + classValue = DataValue.Null; + return false; + } + + /// + public override bool IsSameAs(ISelectable other) => other is MissionRewardSelectable missionRewardSelectable && + missionRewardSelectable.MissionReward == MissionReward; + + /// + public override IModifiable OpenModification() => + new JTokenModifiable(MissionReward, MissionSelectable.SetModified); + + /// + public override ISelectable AddElement(string elementType) + { + var obj = new JObject + { + ["MissionRewardType"] = elementType + }; + Classes.Add(elementType); + var selectable = new JTokenSelectable(MissionSelectable.SetModified, obj, + token => ((JObject)token)["MissionRewardType"]!.Value(), elementType); + Children.Add(selectable); + _missionRewardDefinitions.Add(obj); + return selectable; + } + + /// + public override string Serialize() => MissionReward.ToString(); + + /// + public override DataValue GetValue() => DataValue.From(_missionRewardDefinitions); + + /// + public override string ElementType => "MissionReward"; + } +} \ No newline at end of file diff --git a/Runtime/Missions/Selectables/MissionRewardSelectable.cs.meta b/Runtime/Missions/Selectables/MissionRewardSelectable.cs.meta new file mode 100644 index 0000000..d4552ef --- /dev/null +++ b/Runtime/Missions/Selectables/MissionRewardSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2f64c77f843bd9046bc2e770a25d6d58 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Selectables/MissionSelectable.cs b/Runtime/Missions/Selectables/MissionSelectable.cs new file mode 100644 index 0000000..6e1dfa9 --- /dev/null +++ b/Runtime/Missions/Selectables/MissionSelectable.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.Missions.Modifiables; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Selectables; + +namespace PatchManager.Missions.Selectables +{ + /// + /// A selectable for the main body of a mission + /// + public sealed class MissionSelectable : BaseSelectable + { +#pragma warning disable CS0414 // Field is assigned but its value is never used + private bool _modified; +#pragma warning restore CS0414 // Field is assigned but its value is never used + private bool _deleted; + + /// + /// Marks this part selectable as having been modified any level down + /// + public void SetModified() + { + _modified = true; + } + + /// + /// Marks this part as goneso + /// + public void SetDeleted() + { + SetModified(); + _deleted = true; + } + + /// + /// Creates a new mission selectable from a JObject + /// + /// The JObject to create the selectable from + public MissionSelectable(JObject missionObject) + { + MissionObject = missionObject; + Children = new List(); + Classes = new List(); + foreach (var child in missionObject) + { + Classes.Add(child.Key); + if (child.Key != "missionStages" && child.Key != "ContentBranches") + { + Children.Add(new JTokenSelectable(SetModified, child.Value, child.Key, child.Key)); + } + } + + var stages = (JArray)MissionObject["missionStages"]!; + Children.Add(new StagesSelectable(this, stages)); + if (missionObject.ContainsKey("ContentBranches")) + { + var branches = (JArray)MissionObject["ContentBranches"]!; + Children.Add(new ContentBranchesSelectable(this, branches)); + } + } + + /// + /// The JObject that this selectable represents + /// + public JObject MissionObject; + + /// + public override List Children { get; } + + /// + public override string Name => MissionObject["ID"]!.Value()!; + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + if (MissionObject.TryGetValue(@class, out var jToken)) + { + classValue = DataValue.FromJToken(jToken); + return true; + } + + classValue = DataValue.Null; + return false; + } + + /// + public override bool IsSameAs(ISelectable other) => + other is MissionSelectable selectable && selectable.MissionObject == MissionObject; + + /// + public override IModifiable OpenModification() => new MissionModifiable(this); + + /// + public override ISelectable AddElement(string elementType) => throw new Exception( + "You cannot add elements to the main body of the mission, try using ContentBranches, or missionStages for that"); + + /// + public override string Serialize() => _deleted ? "" : MissionObject.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(MissionObject); + + /// + public override string ElementType => "missions"; + } +} \ No newline at end of file diff --git a/Runtime/Missions/Selectables/MissionSelectable.cs.meta b/Runtime/Missions/Selectables/MissionSelectable.cs.meta new file mode 100644 index 0000000..4c936cb --- /dev/null +++ b/Runtime/Missions/Selectables/MissionSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 81d1b6ada559dd149b12f2bb3acd12e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Selectables/StageSelectable.cs b/Runtime/Missions/Selectables/StageSelectable.cs new file mode 100644 index 0000000..ad7c981 --- /dev/null +++ b/Runtime/Missions/Selectables/StageSelectable.cs @@ -0,0 +1,155 @@ +using System; +using System.Collections.Generic; +using KSP.Game.Missions; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Modifiables; +using PatchManager.SassyPatching.Selectables; + +namespace PatchManager.Missions.Selectables +{ + /// + /// Selectable for a stage in a mission. + /// + public sealed class StageSelectable : BaseSelectable + { + /// + /// The mission selectable that this stage belongs to. + /// + public MissionSelectable MissionSelectable; + + /// + /// The stage object. + /// + public JObject StageObject; + + private int _conditionIndex = -1; + + /// + /// Create a new stage selectable. + /// + /// Mission selectable that this stage belongs to. + /// Stage object. + public StageSelectable(MissionSelectable missionSelectable, JObject stageObject) + { + MissionSelectable = missionSelectable; + StageObject = stageObject; + Children = new List(); + Classes = new List(); + foreach (var child in stageObject) + { + Classes.Add(child.Key); + if (child.Key != "scriptableCondition" && child.Key != "actions" && child.Key != "MissionReward") + { + Children.Add(new JTokenSelectable(MissionSelectable.SetModified, child.Value, child.Key, child.Key)); + } + } + + if (stageObject["scriptableCondition"].Type == JTokenType.Object) + { + if (((JObject)stageObject["scriptableCondition"]!)["ConditionType"]!.Value() == "ConditionSet") + { + _conditionIndex = Children.Count; + Children.Add( + new ConditionSetSelectable(missionSelectable, (JObject)stageObject["scriptableCondition"]!)); + } + else + { + _conditionIndex = Children.Count; + Children.Add(new JTokenSelectable(MissionSelectable.SetModified, stageObject["scriptableCondition"], + "scriptableCondition", "scriptableCondition")); + } + } + + if (stageObject.TryGetValue("MissionReward", out var value)) + { + Children.Add(new MissionRewardSelectable(MissionSelectable, (JObject)value!)); + } + + Children.Add(new ActionsSelectable(MissionSelectable, (JArray)stageObject["actions"]!)); + } + + /// + public override List Children { get; } + + /// + public override string Name => $"_{StageObject["StageID"]!.Value()}"; + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + if (StageObject.TryGetValue(@class, out var jToken)) + { + classValue = DataValue.FromJToken(jToken); + return true; + } + + classValue = DataValue.Null; + return false; + } + + /// + public override bool IsSameAs(ISelectable other) => + other is StageSelectable stageSelectable && stageSelectable.StageObject == StageObject; + + /// + public override IModifiable OpenModification() => new JTokenModifiable(StageObject, MissionSelectable.SetModified); + + /// + public override ISelectable AddElement(string elementType) + { + var conditionType = MissionsTypes.Conditions[elementType]; + // var conditionObject = JObject.FromObject(Activator.CreateInstance(conditionType)); + var conditionObject = new JObject(); + foreach (var (key, value) in JObject.FromObject(Activator.CreateInstance(conditionType))) + { + conditionObject[key] = value; + } + + StageObject["scriptableCondition"] = conditionObject; + if (conditionType == typeof(ConditionSet)) + { + var selectable = new ConditionSetSelectable(MissionSelectable, conditionObject); + if (_conditionIndex > 0) + { + return Children[_conditionIndex] = selectable; + } + + _conditionIndex = Children.Count; + Children.Add(selectable); + return selectable; + } + else + { + var selectable = new JTokenSelectable( + MissionSelectable.SetModified, + conditionObject, + "scriptableCondition", + "scriptableCondition" + ); + + if (_conditionIndex > 0) + { + return Children[_conditionIndex] = selectable; + } + + _conditionIndex = Children.Count; + Children.Add(selectable); + return selectable; + } + } + + /// + public override string Serialize() => StageObject.ToString(); + + /// + public override DataValue GetValue() => DataValue.From(StageObject); + + /// + public override string ElementType => $"_{StageObject["StageID"]!.Value()}"; + } +} \ No newline at end of file diff --git a/Runtime/Missions/Selectables/StageSelectable.cs.meta b/Runtime/Missions/Selectables/StageSelectable.cs.meta new file mode 100644 index 0000000..9840de9 --- /dev/null +++ b/Runtime/Missions/Selectables/StageSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 97711084e4bb3bd499de02c90cc1af38 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Missions/Selectables/StagesSelectable.cs b/Runtime/Missions/Selectables/StagesSelectable.cs new file mode 100644 index 0000000..3656ed0 --- /dev/null +++ b/Runtime/Missions/Selectables/StagesSelectable.cs @@ -0,0 +1,103 @@ +using System.Collections.Generic; +using KSP.Game.Missions.Definitions; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Modifiables; + +namespace PatchManager.Missions.Selectables +{ + /// + /// Selectable for the stages of a mission. + /// + public sealed class StagesSelectable : BaseSelectable + { + /// + /// The mission selectable this stage selectable belongs to. + /// + public MissionSelectable MissionSelectable; + + /// + /// The stages of the mission. + /// + public JArray Stages; + + /// + /// Creates a new stages selectable. + /// + /// Mission selectable this stage selectable belongs to. + /// The stages of the mission. + public StagesSelectable(MissionSelectable selectable, JArray stages) + { + MissionSelectable = selectable; + Stages = stages; + Children = new List(); + Classes = new List(); + foreach (var stage in stages) + { + var obj = (JObject)stage; + var id = obj["StageID"]!.Value(); + var idString = $"_{id}"; + Classes.Add(idString); + Children.Add(new StageSelectable(selectable, obj)); + } + } + + /// + public override List Children { get; } + + /// + public override string Name => "missionStages"; + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + var num = long.Parse(@class[1..]); + foreach (var stage in Stages) + { + var obj = (JObject)stage; + var id = obj["ID"]!.Value(); + if (id != num) continue; + classValue = DataValue.FromJToken(obj); + return true; + } + classValue = DataValue.Null; + return false; + } + + /// + public override bool IsSameAs(ISelectable other) => + other is StagesSelectable stagesSelectable && stagesSelectable.Stages == Stages; + + /// + public override IModifiable OpenModification() => new JTokenModifiable(Stages, MissionSelectable.SetModified); + + /// + public override ISelectable AddElement(string elementType) + { + var num = long.Parse(elementType[1..]); + var obj = new MissionStage + { + StageID = (int)num + }; + var stage = JObject.FromObject(obj); + Classes.Add(elementType); + var selectable = new StageSelectable(MissionSelectable, stage); + Children.Add(selectable); + Stages.Add(stage); + return selectable; + } + + /// + public override string Serialize() => Stages.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(Stages); + + /// + public override string ElementType => "missionStages"; + } +} \ No newline at end of file diff --git a/Runtime/Missions/Selectables/StagesSelectable.cs.meta b/Runtime/Missions/Selectables/StagesSelectable.cs.meta new file mode 100644 index 0000000..b0a358f --- /dev/null +++ b/Runtime/Missions/Selectables/StagesSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 59b0b655453ffbe4797fb034e1c4bf25 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts.meta b/Runtime/Parts.meta new file mode 100644 index 0000000..2e308c7 --- /dev/null +++ b/Runtime/Parts.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c103bac9088649e581b26384a3cfb042 +timeCreated: 1739404438 \ No newline at end of file diff --git a/Runtime/Parts/Attributes.meta b/Runtime/Parts/Attributes.meta new file mode 100644 index 0000000..bad02aa --- /dev/null +++ b/Runtime/Parts/Attributes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 811ba985edd8bcc45bade4e3929fa54f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Attributes/ModuleDataAdapterAttribute.cs b/Runtime/Parts/Attributes/ModuleDataAdapterAttribute.cs new file mode 100644 index 0000000..5eeb700 --- /dev/null +++ b/Runtime/Parts/Attributes/ModuleDataAdapterAttribute.cs @@ -0,0 +1,23 @@ +using System; + +namespace PatchManager.Parts.Attributes +{ + /// + /// Types that take this attribute must inherit from (ISelectable) and must have a constructor that takes the following arguments + /// JObject - ModuleData.DataObject + /// ModuleSelectable - Module + /// + [AttributeUsage(AttributeTargets.Class)] + public class ModuleDataAdapterAttribute : Attribute + { + /// + /// The types this adapter is used for + /// + public readonly Type[] ValidTypes; + /// + /// Mark this class as a custom module data adapter + /// + /// What data types it adapts + public ModuleDataAdapterAttribute(params Type[] validTypes) => ValidTypes = validTypes; + } +} \ No newline at end of file diff --git a/Runtime/Parts/Attributes/ModuleDataAdapterAttribute.cs.meta b/Runtime/Parts/Attributes/ModuleDataAdapterAttribute.cs.meta new file mode 100644 index 0000000..3e6132a --- /dev/null +++ b/Runtime/Parts/Attributes/ModuleDataAdapterAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dcaaa84186701dd42b11957347faa72d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Builtins.meta b/Runtime/Parts/Builtins.meta new file mode 100644 index 0000000..8e4b200 --- /dev/null +++ b/Runtime/Parts/Builtins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 734c42889daacbf408cd8725b7e398b5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Builtins/PartsBuiltins.cs b/Runtime/Parts/Builtins/PartsBuiltins.cs new file mode 100644 index 0000000..2a5c0e4 --- /dev/null +++ b/Runtime/Parts/Builtins/PartsBuiltins.cs @@ -0,0 +1,327 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using KSP.IO; +using KSP.Sim.Definitions; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using UniLinq; + +namespace PatchManager.Parts.Builtins +{ + /// + /// This library contains utilities for working with parts in Patch Manager + /// + [SassyLibrary("builtin","parts")] + [PublicAPI] + public class PartsBuiltins + { + + /// + /// Finds a module in a part data object + /// + /// The part data object + /// The module name + /// The found module or a null value + [SassyMethod("find-module")] + public DataValue FindModule([SassyName("part-object")] Dictionary partObject, [SassyName("module-name")] string moduleName) + { + if (moduleName.StartsWith("PartComponent")) + moduleName = moduleName.Replace("PartComponent", ""); + var modules = partObject["serializedPartModules"].List.Select(x => x.Dictionary); + foreach (var module in modules) + { + if (module["Name"].String.Replace("PartComponent", "") == moduleName) + { + return module; + } + } + + return DataValue.Null; + } + + /// + /// Adds a module to a part data object + /// + /// The part data object + /// The module to add + /// The new part data object + [SassyMethod("add-module")] + public Dictionary AddModule([SassyName("part-object")] Dictionary partObject, Dictionary module) + { + var newObject = new Dictionary(partObject); + newObject["serializedPartModules"].List.Add(module); + return newObject; + } + + /// + /// Removes a module from a part data object + /// + /// The part data object + /// The name of the module to remove + /// The new part data object + [SassyMethod("remove-module")] + public Dictionary RemoveModule([SassyName("part-object")] Dictionary partObject, [SassyName("module-name")] string moduleName) + { + if (moduleName.StartsWith("PartComponent")) + moduleName = moduleName.Replace("PartComponent", ""); + var newObject = new Dictionary(partObject); + var index = -1; + var modules = partObject["serializedPartModules"].List.Select(x => x.Dictionary).ToList(); + for (var i = 0; i < modules.Count; i++) + { + if (modules[i]["Name"].String.Replace("PartComponent", "") != moduleName) + { + continue; + } + + index = i; + break; + } + + if (index >= 0) + { + newObject["serializedPartModules"].List.RemoveAt(index); + } + + return newObject; + } + + /// + /// Replaces a module in a part data object + /// + /// The part data object + /// The name of the module to replace + /// The new module + /// The new part data object + [SassyMethod("replace-module")] + public Dictionary ReplaceModule( + [SassyName("part-object")] Dictionary partObject, + [SassyName("module-name")] string moduleName, + Dictionary module + ) + { + if (moduleName.StartsWith("PartComponent")) + moduleName = moduleName.Replace("PartComponent", ""); + var newObject = new Dictionary(partObject); + var index = -1; + var modules = partObject["serializedPartModules"].List.Select(x => x.Dictionary).ToList(); + for (var i = 0; i < modules.Count; i++) + { + if (modules[i]["Name"].String.Replace("PartComponent", "") != moduleName) + { + continue; + } + + index = i; + break; + } + + if (index >= 0) + { + newObject["serializedPartModules"].List[index] = module; + } + else + { + newObject["serializedPartModules"].List.Add(module); + } + return newObject; + } + + /// + /// Creates a new module object + /// + /// The type of module to create + /// The new module object + /// If the module type is unknown + [SassyMethod("create-module")] + public Dictionary CreateModule(string type) + { + + if (!PartsUtilities.ComponentModules.TryGetValue(type, out var mod)) + { + throw new Exception($"Unknown part module {type}"); + } + var moduleObject = new JObject() + { + ["Name"] = mod.componentModule.Name, + ["ComponentType"] = mod.componentModule.AssemblyQualifiedName, + ["BehaviourType"] = mod.behaviour.AssemblyQualifiedName, + ["ModuleData"] = new JArray() + }; + return DataValue.FromJToken(moduleObject).Dictionary; + } + + + /// + /// Finds a module data object in a part module + /// + /// The part module + /// The name of the module data + /// + [SassyMethod("find-module-data")] + public DataValue FindModuleData([SassyName("part-module")] Dictionary partModule, [SassyName("module-data-name")] string moduleDataName) + { + var data = partModule["ModuleData"].List.Select(x => x.Dictionary); + foreach (var moduleData in data) + { + if (moduleData["Name"].String == moduleDataName) + { + return moduleData; + } + } + return DataValue.Null; + } + + /// + /// Adds a module data object to a part module + /// + /// The part module + /// The module data object + /// The new part module + [SassyMethod("add-module-data")] + public Dictionary AddModuleData([SassyName("part-module")] Dictionary partModule, [SassyName("module-data")] Dictionary moduleData) + { + var newObject = new Dictionary(partModule); + newObject["ModuleData"].List.Add(moduleData); + return newObject; + } + + /// + /// Removes a module data object from a part module + /// + /// The part module + /// The name of the module data object to remove + /// The new part module + [SassyMethod("remove-module-data")] + public Dictionary RemoveModuleData( + [SassyName("part-module")] Dictionary partModule, + [SassyName("module-data-name")] string moduleDataName + ) + { + var newObject = new Dictionary(partModule); + var index = -1; + var modules = partModule["ModuleData"].List.Select(x => x.Dictionary).ToList(); + for (var i = 0; i < modules.Count; i++) + { + if (modules[i]["Name"].String != moduleDataName) + { + continue; + } + + index = i; + break; + } + + if (index >= 0) + { + newObject["ModuleData"].List.RemoveAt(index); + } + + return newObject; + } + + /// + /// Replaces a module data object in a part module + /// + /// The part module + /// The name of the module data object to replace + /// The new module data object + /// The new part module + [SassyMethod("replace-module-data")] + public Dictionary ReplaceModuleData( + [SassyName("part-module")] Dictionary partModule, + [SassyName("module-data-name")] string moduleDataName, + [SassyName("module-data")] Dictionary moduleData + ) + { + var newObject = new Dictionary(partModule); + var index = -1; + var modules = partModule["ModuleData"].List.Select(x => x.Dictionary).ToList(); + for (var i = 0; i < modules.Count; i++) + { + if (modules[i]["Name"].String != moduleDataName) + { + continue; + } + + index = i; + break; + } + + if (index >= 0) + { + newObject["ModuleData"].List[index] = moduleData; + } + else + { + newObject["ModuleData"].List.Add(moduleData); + } + + return newObject; + } + + /// + /// Creates a new module data object + /// + /// The type of module data to create + /// The new module data object + /// If the module data type is unknown + [SassyMethod("create-module-data")] + public Dictionary CreateModuleData(string type) + { + if (!PartsUtilities.DataModules.TryGetValue(type, out var dataModuleType)) + { + throw new Exception($"Unknown data module {type}"); + } + + var instance = (ModuleData)Activator.CreateInstance(dataModuleType); + var dataObject = new JObject + { + ["$type"] = $"{dataModuleType.FullName}, {dataModuleType.Assembly.GetName().Name}" + }; + var otherObject = JObject.Parse(IOProvider.ToJson(instance)); + foreach (var prop in otherObject) + { + dataObject[prop.Key] = prop.Value; + } + var trueType = new JObject + { + ["Name"] = dataModuleType.Name, + ["ModuleType"] = instance.ModuleType.AssemblyQualifiedName, + ["DataType"] = instance.DataType.AssemblyQualifiedName, + ["Data"] = null, + ["DataObject"] = dataObject + }; + return DataValue.FromJToken(trueType).Dictionary; + } + + /// + /// Gets the data object from a module data object + /// + /// The module data object + /// The data object + [SassyMethod("get-data-object")] + public static Dictionary GetDataObject( + [SassyName("module-data")] Dictionary moduleData + ) => moduleData["DataObject"].Dictionary; + + /// + /// Sets the data object in a module data object + /// + /// The module data object + /// The data object + /// The new module data object + [SassyMethod("set-data-object")] + public static Dictionary SetDataObject( + [SassyName("module-data")] Dictionary moduleData, + [SassyName("data-object")] Dictionary dataObject + ) + { + var result = new Dictionary(moduleData); + result["DataObject"] = dataObject; + return result; + } + } +} \ No newline at end of file diff --git a/Runtime/Parts/Builtins/PartsBuiltins.cs.meta b/Runtime/Parts/Builtins/PartsBuiltins.cs.meta new file mode 100644 index 0000000..f4dd33d --- /dev/null +++ b/Runtime/Parts/Builtins/PartsBuiltins.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2674a39de8e2f7448b230fa0ac17b631 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Modifiables.meta b/Runtime/Parts/Modifiables.meta new file mode 100644 index 0000000..72eaaeb --- /dev/null +++ b/Runtime/Parts/Modifiables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cbe3f905cd97db34da0ceca1efc17d4f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Modifiables/PartModifiable.cs b/Runtime/Parts/Modifiables/PartModifiable.cs new file mode 100644 index 0000000..32b95d7 --- /dev/null +++ b/Runtime/Parts/Modifiables/PartModifiable.cs @@ -0,0 +1,51 @@ +using Newtonsoft.Json.Linq; +using PatchManager.Parts.Selectables; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Modifiables; +using Enumerable = UniLinq.Enumerable; + +namespace PatchManager.Parts.Modifiables +{ + /// + /// Represents the modifiable state of a part_json file + /// + public sealed class PartModifiable : CustomJTokenModifiable + { + private PartSelectable _selectable; + internal PartModifiable(PartSelectable selectable) : base(selectable.JObject["data"],selectable.SetModified) + { + _selectable = selectable; + } + + /// + public override DataValue GetFieldValue(string fieldName) + { + var repl = fieldName.Replace("PartComponent", ""); + if (JToken is not JObject jObject) + return DataValue.Null; + if (!jObject.ContainsKey("serializedPartModules")) + return DataValue.Null; + foreach (var module in jObject["serializedPartModules"]) + { + if (module is not JObject moduleObject) continue; + if (moduleObject.ContainsKey("Name") && ((string)moduleObject["Name"])!.Replace("PartComponent", "") == repl) + return DataValue.FromJToken(module); + } + + if (jObject.TryGetValue(fieldName, out var value)) + return DataValue.FromJToken(value); + + return DataValue.Null; + } + + /// + public override void Set(DataValue dataValue) + { + if (dataValue.IsDeletion) + { + _selectable.SetDeleted(); + } + base.Set(dataValue); + } + } +} \ No newline at end of file diff --git a/Runtime/Parts/Modifiables/PartModifiable.cs.meta b/Runtime/Parts/Modifiables/PartModifiable.cs.meta new file mode 100644 index 0000000..afb6a02 --- /dev/null +++ b/Runtime/Parts/Modifiables/PartModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cd113db45260d00418a69ec97e92d702 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/PartsModule.cs b/Runtime/Parts/PartsModule.cs new file mode 100644 index 0000000..2f4d544 --- /dev/null +++ b/Runtime/Parts/PartsModule.cs @@ -0,0 +1,23 @@ +using JetBrains.Annotations; +using PatchManager.Parts.Patchers; +using PatchManager.Shared.Modules; +using SpaceWarp.API.Loading; + +namespace PatchManager.Parts +{ + /// + /// Part patching module. + /// + [UsedImplicitly] + public class PartsModule : BaseModule + { + /// + /// Initialize the module + /// + public override void Init() + { + PartsUtilities.GrabModuleDataAdapters(); + SaveLoad.AddFlowActionToCampaignLoadAfter("Parsing parts text assets"); + } + } +} \ No newline at end of file diff --git a/Runtime/Parts/PartsModule.cs.meta b/Runtime/Parts/PartsModule.cs.meta new file mode 100644 index 0000000..4cc8ee0 --- /dev/null +++ b/Runtime/Parts/PartsModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a4d7c199fb7cae14abaad556c53c4768 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/PartsUtilities.cs b/Runtime/Parts/PartsUtilities.cs new file mode 100644 index 0000000..508f740 --- /dev/null +++ b/Runtime/Parts/PartsUtilities.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using KSP.Sim.Definitions; +using KSP.Sim.impl; +using PatchManager.Parts.Attributes; +using PatchManager.SassyPatching.Interfaces; +using UniLinq; + +namespace PatchManager.Parts +{ + /// + /// Utilities for parts patching. + /// + public static class PartsUtilities + { + private static Dictionary _componentModules; + + private static void BuildComponentModuleDictionary() + { + _componentModules = new(); + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + foreach (var type in assembly.GetTypes().Where(type => !type.IsAbstract).Where(type => type.IsSubclassOf(typeof(PartComponentModule)))) + { + try + { + var mod = (PartComponentModule)Activator.CreateInstance(type); + var behaviour = mod.PartBehaviourModuleType; + var tuple = (type, behaviour); + var name1 = type.Name; + var name2 = name1.Replace("PartComponent", ""); + _componentModules[name1] = tuple; + if (!name1.Equals(name2)) + { + _componentModules[name2] = tuple; + } + } + catch + { + //ignored + } + } + } + } + + internal static IReadOnlyDictionary ComponentModules + { + get + { + if (_componentModules == null) + { + BuildComponentModuleDictionary(); + } + + return _componentModules; + } + } + + + private static Dictionary _dataModules; + + private static void BuildDataModuleDictionary() + { + _dataModules = new(); + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + foreach (var type in assembly.GetTypes().Where(type => !type.IsAbstract) + .Where(type => type.IsSubclassOf(typeof(ModuleData)))) + { + var name1 = type.Name; + var name2 = name1.Replace("Data_", ""); + _dataModules[name1] = type; + if (!name1.Equals(name2)) + { + _dataModules[name2] = type; + } + } + } + } + + internal static IReadOnlyDictionary DataModules + { + get + { + if (_dataModules == null) + { + BuildDataModuleDictionary(); + } + + return _dataModules; + } + } + + internal static readonly Dictionary ModuleDataAdapters = new(); + + internal static void GrabModuleDataAdapters() + { + foreach (var type in AppDomain.CurrentDomain.GetAssemblies() + .SelectMany(x => x.GetTypes()) + .Where(x => x.GetCustomAttributes(typeof(ModuleDataAdapterAttribute), + false) + .Any()) + .Select(x => (type: x, attr: (ModuleDataAdapterAttribute)x.GetCustomAttributes(typeof(ModuleDataAdapterAttribute), + false) + .FirstOrDefault()))) + { + foreach (var dataType in type.attr.ValidTypes) + { + ModuleDataAdapters[dataType] = type.type; + } + } + } + + /// + /// Registers a module data adapter for the given types + /// + /// The types that this adapter is valid for + /// The type of the adapter + public static void RegisterModuleDataAdapter(params Type[] validTargets) where T : ISelectable + { + foreach (var type in validTargets) + { + ModuleDataAdapters[type] = typeof(T); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Parts/PartsUtilities.cs.meta b/Runtime/Parts/PartsUtilities.cs.meta new file mode 100644 index 0000000..a76fae0 --- /dev/null +++ b/Runtime/Parts/PartsUtilities.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 14edaa2f87db309409a0dd3e5f229416 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Patchers.meta b/Runtime/Parts/Patchers.meta new file mode 100644 index 0000000..98b02cc --- /dev/null +++ b/Runtime/Parts/Patchers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bfc19625c02002649a7220e30d212fba +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Patchers/OABUtilsPatcher.cs b/Runtime/Parts/Patchers/OABUtilsPatcher.cs new file mode 100644 index 0000000..4447671 --- /dev/null +++ b/Runtime/Parts/Patchers/OABUtilsPatcher.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using KSP.OAB; + +namespace PatchManager.Parts.Patchers +{ + internal class OabUtilsPatcher + { + /// + /// This is a map of part names to icon names. It is populated by the PartDataDeserializePatcher. + /// + internal static Dictionary PartIconMap { get; } = new(); + } +} \ No newline at end of file diff --git a/Runtime/Parts/Patchers/OABUtilsPatcher.cs.meta b/Runtime/Parts/Patchers/OABUtilsPatcher.cs.meta new file mode 100644 index 0000000..c32f359 --- /dev/null +++ b/Runtime/Parts/Patchers/OABUtilsPatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 34ba4f1d28221bf4a9326a2fb6a99960 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Patchers/PartModuleLoadPatcher.cs b/Runtime/Parts/Patchers/PartModuleLoadPatcher.cs new file mode 100644 index 0000000..4f8d9a5 --- /dev/null +++ b/Runtime/Parts/Patchers/PartModuleLoadPatcher.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using System.Reflection; +using KSP.Game; +using KSP.OAB; +using KSP.Sim; +using KSP.Sim.Definitions; +using KSP.Sim.impl; +using PatchManager.Shared; +using UniLinq; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace PatchManager.Parts.Patchers +{ + internal static class PartModuleLoadPatcher + { + /// + /// This is a map of part names to prefab names. It is populated by the PartDataDeserializePatcher. + /// + internal static Dictionary PartPrefabMap { get; } = new(); + + internal static void ApplyOnGameObject(ref GameObject gameObject, PartData partData) + { + var obj = gameObject; + + if (PartPrefabMap.TryGetValue(partData.partName, out var prefabName)) + { + var prefab = GameManager.Instance.Assets.LoadAssetAsync(prefabName).WaitForCompletion(); + obj = Object.Instantiate(prefab); + } + + foreach (var module in partData.serializedPartModules) + { + var behaviourType = module.BehaviourType; + // Debug.Log($"ApplyOnGameObject - {partData.partName} testing {behaviourType.FullName}"); + if (obj.GetComponent(behaviourType) != null) + { + continue; + } + + // Debug.Log($"ApplyOnGameObject - {partData.partName} adding {behaviourType.FullName}"); + var instance = obj.AddComponent(behaviourType); + Logging.LogInfo($"Attempting to setup serialized fields on {partData.partName} of type {behaviourType}"); + foreach (var field in behaviourType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic) + .Concat(behaviourType.GetFields(BindingFlags.Public | BindingFlags.Instance))) + { + // Logging.LogInfo($"Found field: {field.Name} of type {field.FieldType}"); + if (!field.GetCustomAttributes(typeof(SerializeField), false).Any()) + { + continue; + } + + // Logging.LogInfo($"Field has SerializeField attribute"); + if (!field.FieldType.IsSubclassOf(typeof(ModuleData))) + { + continue; + } + + // Logging.LogInfo($"Field type {field.FieldType} is subclass of ModuleData, setting value"); + var data = module.ModuleData.FirstOrDefault(x => x.DataObject.GetType() == field.FieldType); + data.DataObject?.RebuildDataContext(); + field.SetValue(instance, data.DataObject); + } + } + + foreach (var component in obj.GetComponents()) + { + // Debug.Log($"ApplyOnGameObject - {partData.partName} checking {component.GetType().FullName}"); + var t = component.GetType(); + if (partData.serializedPartModules.All(x => x.BehaviourType != t)) + { + // Debug.Log($"ApplyOnGameObject - {partData.partName} removing {component.GetType().FullName}"); + Object.Destroy(component); + } + } + + gameObject = obj; + } + } +} \ No newline at end of file diff --git a/Runtime/Parts/Patchers/PartModuleLoadPatcher.cs.meta b/Runtime/Parts/Patchers/PartModuleLoadPatcher.cs.meta new file mode 100644 index 0000000..a519bb3 --- /dev/null +++ b/Runtime/Parts/Patchers/PartModuleLoadPatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 71eef599aab829b418ababe68b4d4157 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Patchers/UpdateSavedVesselPartDefinitions.cs b/Runtime/Parts/Patchers/UpdateSavedVesselPartDefinitions.cs new file mode 100644 index 0000000..000a5fd --- /dev/null +++ b/Runtime/Parts/Patchers/UpdateSavedVesselPartDefinitions.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using KSP.Game; +using KSP.Game.Load; +using KSP.Sim.State; +using PatchManager.Shared; +using ReduxLib.GameInterfaces; +using UniLinq; + +namespace PatchManager.Parts.Patchers +{ + internal class UpdateSavedVesselPartDefinitions : IFlowAction + { + private LoadGameData _loadGameData; + + public UpdateSavedVesselPartDefinitions(LoadGameData loadGameData) + { + _loadGameData = loadGameData; + } + public string Name => "Updating saved vessel part definitions"; + public string Description => "Updating saved vessel part definitions"; + public void DoAction(Action resolve, Action reject) + { + if (_loadGameData.SavedGame.Vessels == null) + { + resolve(); + return; + } + List toRemove = new(); + int idx = 0; + foreach (var vessel in _loadGameData.SavedGame.Vessels) + { + // Lets change only a few things + // Add modules, change resource containers + foreach (var part in vessel.parts) + { + var name = part.partName; + var def = GameManager.Instance.Game.Parts.Get(name); + if (def == null) + { + Logging.LogWarning($"Invalid part {name} found on vessel {vessel.AssemblyDefinition.assemblyName}, removing vessel from save file\n"); + toRemove.Add(idx); + break; + } + for (var i = part.PartModulesState.Count - 1; i >= 0; i--) + { + var i2 = i; + if (def.data.serializedPartModules.All(x => x.Name != part.PartModulesState[i2].Name)) + { + part.PartModulesState.RemoveAt(i); + } + } + + foreach (var mod in def.data.serializedPartModules) + { + if (part.PartModulesState.All(x => x.Name != mod.Name)) + { + part.PartModulesState.Add(mod); + } + } + + foreach (var resource in def.data.resourceContainers) + { + if (!part.partState.resources.ContainsKey(resource.name)) + { + part.partState.resources[resource.name] = new ContainedResourceState + { + name = resource.name, + storedUnits = resource.initialUnits, + capacityUnits = resource.capacityUnits + }; + } + } + } + idx += 1; + } + + toRemove.Reverse(); + var vesselList = _loadGameData.SavedGame.Vessels.ToList(); + foreach (var removal in toRemove) + { + vesselList.RemoveAt(removal); + } + _loadGameData.SavedGame.Vessels = vesselList.ToArray(); + resolve(); + } + } +} \ No newline at end of file diff --git a/Runtime/Parts/Patchers/UpdateSavedVesselPartDefinitions.cs.meta b/Runtime/Parts/Patchers/UpdateSavedVesselPartDefinitions.cs.meta new file mode 100644 index 0000000..5c7dd4f --- /dev/null +++ b/Runtime/Parts/Patchers/UpdateSavedVesselPartDefinitions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 31826cfa2c6fe49409e0e2742d7643f9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Rulesets.meta b/Runtime/Parts/Rulesets.meta new file mode 100644 index 0000000..df984e8 --- /dev/null +++ b/Runtime/Parts/Rulesets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0cd9c7ba5ed1d6f4ab59463509239c1d +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Rulesets/PartsRuleset.cs b/Runtime/Parts/Rulesets/PartsRuleset.cs new file mode 100644 index 0000000..2ac6b6f --- /dev/null +++ b/Runtime/Parts/Rulesets/PartsRuleset.cs @@ -0,0 +1,111 @@ +using System.Collections.Generic; +using KSP.Game; +using KSP.IO; +using KSP.OAB; +using KSP.Sim; +using KSP.Sim.Definitions; +using KSP.Sim.ResourceSystem; +using Newtonsoft.Json.Linq; +using PatchManager.Parts.Selectables; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; +using UnityEngine; + +namespace PatchManager.Parts.Rulesets +{ + /// + /// The `:parts` ruleset used by sassy patching + /// + [PatcherRuleset("parts", "parts_data")] + public class PartsRuleset : IPatcherRuleSet + { + /// + public bool Matches(string label) => label == "parts_data"; + + /// + /// Converts the part json to an ISelectable following this ruleset + /// + /// + /// The name of the file (unused) + /// The part json + /// An ISelectable that follows the part ruleset + public ISelectable ConvertToSelectable(string type, string name, string jsonData) + { + return new PartSelectable(jsonData); + } + /// + /// + /// Create a new part asset + /// + /// The arguments for the part asset, only one argument: name + /// The part asset creator + public INewAsset CreateNew(List dataValues) + { + var name = dataValues[0].String; + var internalPartData = new PartData + { + partName = name, + angularDrag = 0, + coMassOffset = Vector3.zero, + coPressureOffset = Vector3.zero, + mass = 0, + maximumDrag = 0, + maxTemp = 0, + author = "", + bodyLiftOnlyUnattachedLift = false, + bodyLiftOnlyAttachName = "", + buoyancy = 0, + buoyancyUseSine = false, + breakingForce = 0, + breakingTorque = 0, + category = PartCategories.none, + family = "", + coBuoyancy = Vector3.zero, + coDisplacement = Vector3.zero, + oabEditorCategory = OABEditorPartCategory.NONE, + partType = AssemblyPartTypeFilter.Rocket, + cost = 0, + crashTolerance = 0, + crewCapacity = 0, + emissiveConstant = 0, + explosionPotential = 0, + fuelCrossFeed = false, + heatConductivity = 0, + inverseStageCarryover = false, + isCompound = false, + maxLength = 0, + radiatorHeadroom = 0, + radiatorMax = 0, + physicsMode = PartPhysicsModes.None, + sizeCategory = MetaAssemblySizeFilterType.XS, + skinMassPerArea = 0, + skinMaxTemp = 0, + skinInternalConductionMult = 0, + stageOffset = 0, + stageType = AssemblyPartStageType.None, + tags = "", + stagingIconAssetAddress = "", + attachRules = AttachRules.Defaults(), + attachNodes = new List(), + resourceContainers = new List(), + resourceCosts = new List(), + serializedPartModules = new List(), + resourceSummary = new SerializedResourceInfo(), + PAMModuleSortOverride = new List(), + PAMModuleVisualsOverride = new List(), + AllowKinematicPhysicsIfIntersectTerrain = false + }; + var internalJson = IOProvider.ToJson(internalPartData); + var internalJObject = JObject.Parse(internalJson); + var externalJObject = new JObject + { + ["version"] = "0.3", + ["useExternalData"] = false, + ["data"] = internalJObject + }; + return new NewGenericAsset("parts_data", name, new PartSelectable(externalJObject.ToString())); + } + } +} \ No newline at end of file diff --git a/Runtime/Parts/Rulesets/PartsRuleset.cs.meta b/Runtime/Parts/Rulesets/PartsRuleset.cs.meta new file mode 100644 index 0000000..bf49ef9 --- /dev/null +++ b/Runtime/Parts/Rulesets/PartsRuleset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2f0c7cc291827104e905097eb21ef5f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Selectables.meta b/Runtime/Parts/Selectables.meta new file mode 100644 index 0000000..82c891d --- /dev/null +++ b/Runtime/Parts/Selectables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 21e212a5f6ac05d48941b325cefafb1b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Selectables/DataEngineSelectable.cs b/Runtime/Parts/Selectables/DataEngineSelectable.cs new file mode 100644 index 0000000..db7c9ba --- /dev/null +++ b/Runtime/Parts/Selectables/DataEngineSelectable.cs @@ -0,0 +1,136 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using KSP.Modules; +using Newtonsoft.Json.Linq; +using PatchManager.Parts.Attributes; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Modifiables; +using PatchManager.SassyPatching.Selectables; + +namespace PatchManager.Parts.Selectables +{ + /// + /// Represents a selectable for the selection and transformation of Data_Engine + /// + [ModuleDataAdapter(typeof(Data_Engine))] + [UsedImplicitly] + public sealed class DataEngineSelectable : BaseSelectable + { + /// + /// The serialized data for this selectable + /// + public readonly JObject SerializedData; + + /// + /// The part selectable that owns this selectable + /// + public readonly PartSelectable Selectable; + + /// + /// Initialize the selectable + /// + /// Module data + /// Module selectable + public DataEngineSelectable(JObject moduleData, ModuleSelectable moduleSelectable) + { + SerializedData = (JObject)moduleData["DataObject"]; + Name = "Data_Engine"; + Selectable = moduleSelectable.Selectable; + ElementType = moduleData["Name"].Value(); + Classes = new(); + Children = new(); + foreach (var field in SerializedData) + { + Classes.Add(field.Key); + if (field.Value.Type == JTokenType.Object) + { + Children.Add(new JTokenSelectable(Selectable.SetModified, field.Value, field.Key, field.Key)); + } + } + + var index = 0; + List removals = new(); + foreach (var jToken in (JArray)SerializedData["engineModes"]) + { + var currentIdx = index++; + if (jToken.Type is JTokenType.Null or JTokenType.None) + { + removals.Add(currentIdx); + continue; + } + var mode = (JObject)jToken; + Classes.Add(mode["engineID"].Value()); + Children.Add(new JTokenSelectable(Selectable.SetModified,mode,m => m["engineID"].Value(),"engine_mode")); + } + + removals.Reverse(); + foreach (var idx in removals) + ((JArray)SerializedData["engineModes"])[idx].Remove(); + } + + /// + public override List Children { get; } + + /// + public override string Name { get; } + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + if (SerializedData.TryGetValue(@class, out var value)) + { + classValue = DataValue.FromJToken(value); + return true; + } + + foreach (var jToken in (JArray)SerializedData["engineModes"]) + { + var mode = (JObject)jToken; + if (mode["engineID"].Value() != @class) + { + continue; + } + + classValue = DataValue.FromJToken(mode); + return true; + } + + classValue = DataValue.Null; + return false; + } + + /// + public override bool IsSameAs(ISelectable other) => + (other is DataEngineSelectable dataEngineSelectable) && + SerializedData == dataEngineSelectable.SerializedData; + + /// + public override IModifiable OpenModification() => new JTokenModifiable(SerializedData, Selectable.SetModified); + + /// + public override ISelectable AddElement(string elementType) + { + var engineModeData = new Data_Engine.EngineMode() + { + engineID = elementType + }; + var json = JObject.FromObject(engineModeData); + ((JArray)SerializedData["engineModes"]).Add(json); + return new JTokenSelectable(Selectable.SetModified, json, mode => mode["engineID"].Value(), + "engine_mode"); + } + + /// + public override string Serialize() => SerializedData.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(SerializedData); + + /// + public override string ElementType { get; } + } +} \ No newline at end of file diff --git a/Runtime/Parts/Selectables/DataEngineSelectable.cs.meta b/Runtime/Parts/Selectables/DataEngineSelectable.cs.meta new file mode 100644 index 0000000..7ba7b9d --- /dev/null +++ b/Runtime/Parts/Selectables/DataEngineSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c4c31f55bb87e7041bbd1f55e7964d73 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Selectables/ModuleSelectable.cs b/Runtime/Parts/Selectables/ModuleSelectable.cs new file mode 100644 index 0000000..2bdd429 --- /dev/null +++ b/Runtime/Parts/Selectables/ModuleSelectable.cs @@ -0,0 +1,138 @@ +using System; +using System.Collections.Generic; +using KSP.IO; +using KSP.Sim.Definitions; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Modifiables; +using PatchManager.SassyPatching.Selectables; + +namespace PatchManager.Parts.Selectables +{ + /// + /// Represents the selectable data in a part module; + /// + public sealed class ModuleSelectable : BaseSelectable + { + /// + /// The serialized data for this selectable + /// + public readonly JToken SerializedData; + + /// + /// The part selectable that owns this selectable + /// + public readonly PartSelectable Selectable; + + private Dictionary _dataIndices; + + /// + public ModuleSelectable(JToken token, PartSelectable selectable) + { + SerializedData = token; + Selectable = selectable; + _dataIndices = new Dictionary(); + ElementType = ((string)token["Name"]).Replace("PartComponent", ""); + Name = ElementType; + Classes = new(); + Children = new(); + Classes.Add("ModuleData"); + // Now we go down the list in the data type + var data = (JArray)token["ModuleData"]; + var index = 0; + foreach (var moduleData in data) + { + _dataIndices[moduleData["Name"].Value()] = index++; + Classes.Add(moduleData["Name"].Value()); + // Where we are going to have to add children ree + // TODO: Add a specialization for ModuleEngine + Children.Add(GetSelectable((JObject)moduleData)); + } + } + + private ISelectable GetSelectable(JObject moduleData) + { + var type = Type.GetType(moduleData["DataType"].Value()); + if (type != null && PartsUtilities.ModuleDataAdapters.TryGetValue(type, out var adapterType)) + { + return (ISelectable)Activator.CreateInstance(adapterType, moduleData, this); + } + return new JTokenSelectable(Selectable.SetModified, moduleData["DataObject"], moduleData["Name"].Value()); + } + + /// + public override List Children { get; } + + /// + public override string Name { get; } + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) { + + if (_dataIndices.TryGetValue(@class.Replace("PartComponent", ""), out var index)) + { + classValue = DataValue.FromJToken(SerializedData["ModuleData"][index]["DataObject"]); + return true; + } + classValue = null; + return false; + } + + /// + public override string ElementType { get; } + + + + /// + public override bool IsSameAs(ISelectable other) => + other is ModuleSelectable moduleSelectable && moduleSelectable.SerializedData == SerializedData; + + /// + public override IModifiable OpenModification() + { + return new JTokenModifiable(SerializedData, Selectable.SetModified); + } + + /// + public override ISelectable AddElement(string elementType) + { + if (!PartsUtilities.DataModules.TryGetValue(elementType, out var dataModuleType)) + { + throw new Exception($"Unknown data module {elementType}"); + } + Selectable.SetModified(); + var instance = (ModuleData)Activator.CreateInstance(dataModuleType); + var dataObject = new JObject + { + ["$type"] = $"{dataModuleType.FullName}, {dataModuleType.Assembly.GetName().Name}" + }; + var otherObject = JObject.Parse(IOProvider.ToJson(instance)); + foreach (var prop in otherObject) + { + dataObject[prop.Key] = prop.Value; + } + var trueType = new JObject + { + ["Name"] = dataModuleType.Name, + ["ModuleType"] = instance.ModuleType.AssemblyQualifiedName, + ["DataType"] = instance.DataType.AssemblyQualifiedName, + ["Data"] = null, + ["DataObject"] = dataObject + }; + (SerializedData["ModuleData"] as JArray)?.Add(trueType); + Classes.Add(dataModuleType.Name); + var selectable = GetSelectable(trueType); + Children.Add(selectable); + return selectable; + } + + /// + public override string Serialize() => SerializedData.ToString(); + /// + public override DataValue GetValue() => DataValue.FromJToken(SerializedData); + } +} \ No newline at end of file diff --git a/Runtime/Parts/Selectables/ModuleSelectable.cs.meta b/Runtime/Parts/Selectables/ModuleSelectable.cs.meta new file mode 100644 index 0000000..30ac962 --- /dev/null +++ b/Runtime/Parts/Selectables/ModuleSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d9a3cfd82300b5049b477f5aaa34d61e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Selectables/PartSelectable.cs b/Runtime/Parts/Selectables/PartSelectable.cs new file mode 100644 index 0000000..c8d524d --- /dev/null +++ b/Runtime/Parts/Selectables/PartSelectable.cs @@ -0,0 +1,159 @@ +using System; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using Newtonsoft.Json.Linq; +using PatchManager.Parts.Modifiables; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Selectables; +using UniLinq; + +namespace PatchManager.Parts.Selectables +{ + /// + /// Represents a selectable for selection and transformation of part data + /// + public sealed class PartSelectable : BaseSelectable + { + private bool _modified; + private bool _deleted; + + /// + /// Marks this part selectable as having been modified any level down + /// + public void SetModified() + { + _modified = true; + } + + /// + /// Marks this part as goneso + /// + public void SetDeleted() + { + SetModified(); + _deleted = true; + } + + private readonly string _originalData; + internal readonly JObject JObject; + private static readonly Regex Sanitizer = new("[^a-zA-Z0-9 -_]"); + private static string Sanitize(string str) => Sanitizer.Replace(str, ""); + private readonly Dictionary _moduleIndices; + private static JArray _serializedPartModules; + + internal PartSelectable(string data) + { + _originalData = data; + JObject = JObject.Parse(data); + _moduleIndices = new Dictionary(); + Classes = new List(); + Children = new List(); + var partData = JObject["data"]; + Name = (string)partData["partName"]; + foreach (var tag in ((string)partData["tags"]).Split(' ')) + { + Classes.Add(Sanitize(tag)); + } + + var serializedPartModules = partData["serializedPartModules"]; + _serializedPartModules = serializedPartModules as JArray; + var index = 0; + foreach (var module in serializedPartModules) + { + // var moduleData = module["ModuleData"]; + _moduleIndices[module["Name"].Value().Replace("PartComponent", "")] = index++; + Classes.Add(module["Name"].Value().Replace("PartComponent", "")); + Classes.Add(module["Name"].Value()); + // Classes.Add((string)moduleData["name"]); + Children.Add(new ModuleSelectable(module,this)); + } + Children.Add(new ResourceContainersSelectable((JArray)partData["resourceContainers"],this)); + // I'd add more but meh, too much work atm for me to then have to run simple tests, this is the MVP + // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop + foreach (JProperty child in partData) + { + if (child.Name != "resourceContainers") + { + Children.Add(new JTokenSelectable(SetModified, child.Value, child.Name)); + } + } + } + + /// + public override List Children { get; } + + /// + public override string Name { get; } + + /// + public override List Classes { get; } + + private DataValue ConcatenateModuleData(int index) + { + DataValue value = new DataValue(DataValue.DataType.Dictionary, new Dictionary()); + foreach (var data in _serializedPartModules[index]["ModuleData"]) + { + var dataObject = DataValue.FromJToken(data["DataObject"]); + foreach (var kv in dataObject.Dictionary.Where(kv => kv.Key != "$type")) + { + value.Dictionary[kv.Key] = kv.Value; + } + } + return value; + } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + if (_moduleIndices.TryGetValue(@class.Replace("PartComponent", ""), out var index)) + { + classValue = ConcatenateModuleData(index); + return true; + } + classValue = null; + return false; + } + + /// + public override string ElementType => "parts_data"; + + /// + public override bool IsSameAs(ISelectable other) => other is PartSelectable ps && ps.Name == Name; + + /// + public override IModifiable OpenModification() + { + return new PartModifiable(this); + } + + /// + public override ISelectable AddElement(string elementType) + { + if (!PartsUtilities.ComponentModules.TryGetValue(elementType, out var mod)) + { + throw new Exception($"Unknown part module {elementType}"); + } + SetModified(); + var moduleObject = new JObject() + { + ["Name"] = mod.componentModule.Name, + ["ComponentType"] = mod.componentModule.AssemblyQualifiedName, + ["BehaviourType"] = mod.behaviour.AssemblyQualifiedName, + ["ModuleData"] = new JArray() + }; + (JObject["data"]["serializedPartModules"] as JArray)?.Add(moduleObject); + var selectable = new ModuleSelectable(moduleObject, this); + Classes.Add(elementType.Replace("PartComponent", "")); + Children.Add(selectable); + return selectable; + } + + + /// + public override string Serialize() => _modified ? _deleted ? "" : JObject.ToString() : _originalData; + + /// + public override DataValue GetValue() => OpenModification().Get(); + } +} \ No newline at end of file diff --git a/Runtime/Parts/Selectables/PartSelectable.cs.meta b/Runtime/Parts/Selectables/PartSelectable.cs.meta new file mode 100644 index 0000000..8025e6d --- /dev/null +++ b/Runtime/Parts/Selectables/PartSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f2c3b4b7c9b5a8f44963929409a3e222 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Selectables/ResourceContainerSelectable.cs b/Runtime/Parts/Selectables/ResourceContainerSelectable.cs new file mode 100644 index 0000000..45d29f8 --- /dev/null +++ b/Runtime/Parts/Selectables/ResourceContainerSelectable.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching.Selectables; + +namespace PatchManager.Parts.Selectables +{ + /// + /// A selectable that operates on resource container objects specifically + /// + public sealed class ResourceContainerSelectable : JTokenSelectable + { + internal ResourceContainerSelectable(JObject container, PartSelectable selectable) + : base(selectable.SetModified, container, "resource_container") + { + Classes.Add((string)container["name"]); + } + } +} \ No newline at end of file diff --git a/Runtime/Parts/Selectables/ResourceContainerSelectable.cs.meta b/Runtime/Parts/Selectables/ResourceContainerSelectable.cs.meta new file mode 100644 index 0000000..fb558ad --- /dev/null +++ b/Runtime/Parts/Selectables/ResourceContainerSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a6dece8091cf70f4ead526c349e5ff39 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Parts/Selectables/ResourceContainersSelectable.cs b/Runtime/Parts/Selectables/ResourceContainersSelectable.cs new file mode 100644 index 0000000..0668883 --- /dev/null +++ b/Runtime/Parts/Selectables/ResourceContainersSelectable.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; + +namespace PatchManager.Parts.Selectables +{ + /// + /// Represents the resourceContainers field of a part json as a selectable + /// + public sealed class ResourceContainersSelectable : BaseSelectable + { + private readonly JArray _containers; + private PartSelectable _selectable; + private Dictionary _resourceIndices; + + internal ResourceContainersSelectable(JArray containers, PartSelectable selectable) + { + _containers = containers; + _resourceIndices = new Dictionary(); + Children = new(); + ElementType = "resourceContainers"; + Classes = new(); + Name = "resourceContainers"; + _selectable = selectable; + var index = 0; + foreach (var container in containers) + { + _resourceIndices[(container as JObject)?["name"].Value() ?? string.Empty] = index++; + Classes.Add((container as JObject)?["name"].Value()); + Children.Add(new ResourceContainerSelectable(container as JObject, selectable)); + } + } + + /// + public override List Children { get; } + + /// + public override string Name { get; } + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + classValue = null; + if (_resourceIndices.TryGetValue(@class, out var index)) + { + classValue = DataValue.FromJToken(_containers[index]); + return true; + } + + return false; + } + + /// + public override string ElementType { get; } + + /// + public override bool IsSameAs(ISelectable other) => + other is ResourceContainersSelectable resourceContainersSelectable && + resourceContainersSelectable._containers == _containers; + + /// + public override IModifiable OpenModification() => null; + + /// + public override ISelectable AddElement(string elementType) + { + _selectable.SetModified(); + var obj = JObject.FromObject(new + { + name = elementType, + capacityUnits = 0.0, + initialUnits = 0.0, + NonStageable = false + }); + _containers.Add(obj); + var child = new ResourceContainerSelectable(obj, _selectable); + Children.Add(child); + // Console.WriteLine($"Added container: {obj}"); + return child; + } + + /// + public override string Serialize() => _containers.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(_containers); + } +} \ No newline at end of file diff --git a/Runtime/Parts/Selectables/ResourceContainersSelectable.cs.meta b/Runtime/Parts/Selectables/ResourceContainersSelectable.cs.meta new file mode 100644 index 0000000..46bfdc1 --- /dev/null +++ b/Runtime/Parts/Selectables/ResourceContainersSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2e89f745f511e8d4598045d0ee08b12a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/PatchManager.Resources.meta b/Runtime/PatchManager.Resources.meta new file mode 100644 index 0000000..e644694 --- /dev/null +++ b/Runtime/PatchManager.Resources.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2ee6e2f2896a32f409dde43c19b98915 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/PatchManager.Resources/NonStageableResourcesUIController.cs b/Runtime/PatchManager.Resources/NonStageableResourcesUIController.cs new file mode 100644 index 0000000..408e7dd --- /dev/null +++ b/Runtime/PatchManager.Resources/NonStageableResourcesUIController.cs @@ -0,0 +1,113 @@ +using System; +using KSP.Game; +using KSP.Messages; +using KSP.Sim.impl; +using KSP.Sim.ResourceSystem; +using PatchManager.Shared; +using UnityEngine; + +namespace PatchManager.Resources +{ + /// + /// Handles dynamic resizing of non-stageable resources flight HUD window based on number of resources + /// + public class NonStageableResourcesUIController : KerbalMonoBehaviour + { + private const string NON_STAGEABLE_RESOURCES_UI_PANEL_PATH = "GameManager/Default Game Instance(Clone)/UI Manager(Clone)/Scaled Main Canvas/FlightHudRoot(Clone)/NonStageableResources(Clone)/KSP2UIWindow/Root/UIPanel"; + private VesselComponent? _activeVessel; + private GameObject? _nsResourcesUI; + private bool _needNsUiUpdate = false; + + private void Start() + { + Game.Messages.PersistentSubscribe(OnVesselChanged); + } + + private void OnDestroy() + { + if (IsGameShuttingDown) + return; + Game.Messages.Unsubscribe(OnVesselChanged); + } + + private void Update() + { + // Get active vessel + _activeVessel = Game?.ViewController?.GetActiveSimVessel(); + + if (_activeVessel is null) + return; + + if (!_needNsUiUpdate) return; + + _needNsUiUpdate = false; + + // Update Non Stageable Resources UI size + UpdateNonStageableResourcesUI(); + } + + private void OnVesselChanged(MessageCenterMessage msg) + { + if (msg is not VesselChangedMessage vesselChangedMessage || vesselChangedMessage == null) + return; + + _needNsUiUpdate = true; + } + + /// + /// Updates the height & position of the non-stageable resources UI + /// + /// + private void UpdateNonStageableResourcesUI() + { + // Get number of non-stageable resources in the active vessel + int nsResourcesCount = GetNonStageableResourcesCount(_activeVessel); + + Logging.LogInfo( + $"Updating the Non-Stageable Resource UI. Found {nsResourcesCount} Resources to display."); + + // Find the non-stageable resources window game object + _nsResourcesUI = + GameObject.Find( + NON_STAGEABLE_RESOURCES_UI_PANEL_PATH); + + if (_nsResourcesUI == null) return; + + // Number of resources above the default maximum of 2 (EC & Monoprop) + var extraResources = Math.Max(0, nsResourcesCount - 2); + + // Get the UI object's RectTransform + var rect = _nsResourcesUI.GetComponent(); + + // Increase the UI object's vertical size + rect.sizeDelta = new Vector2(0, 30 * extraResources); + + // Shift the UI object down + rect.localPosition = extraResources * 15 * Vector3.down; + } + + /// + /// Returns the number of non-stageable resources present on the vessel + /// + private int GetNonStageableResourcesCount(VesselComponent vessel) + { + var count = 0; + + var controlOwner = vessel.GetControlOwner(); + + if (controlOwner == null || controlOwner.PartOwner == null) return count; + + var containerGroup = controlOwner.PartOwner.ContainerGroup; + + foreach (var containedResourceData in containerGroup.GetAllResourcesContainedData()) + { + var definitionData = + Game.ResourceDefinitionDatabase.GetDefinitionData(containedResourceData.ResourceID); + if (definitionData.resourceProperties.NonStageable) + ++count; + } + + return count; + } + } +} \ No newline at end of file diff --git a/Runtime/PatchManager.Resources/NonStageableResourcesUIController.cs.meta b/Runtime/PatchManager.Resources/NonStageableResourcesUIController.cs.meta new file mode 100644 index 0000000..5accb5c --- /dev/null +++ b/Runtime/PatchManager.Resources/NonStageableResourcesUIController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e629365ec56445838b8a76a8c4833398 +timeCreated: 1739537932 \ No newline at end of file diff --git a/Runtime/PatchManager.Resources/ResourcesModule.cs b/Runtime/PatchManager.Resources/ResourcesModule.cs new file mode 100644 index 0000000..a7258dd --- /dev/null +++ b/Runtime/PatchManager.Resources/ResourcesModule.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; +using KSP.Game; +using Newtonsoft.Json.Linq; +using PatchManager.Shared; +using PatchManager.Shared.Modules; +using Unity.VisualScripting; +using UnityEngine.AddressableAssets; +using UnityEngine; + +namespace PatchManager.Resources +{ + /// + /// Resource patching module. + /// + [UsedImplicitly] + public class ResourcesModule : BaseModule + { + /// + /// Implement the resource units from https://github.com/KSP2Community/CommunityResources + /// + internal static readonly Dictionary ResourceUnits = new(); + + + public override void Load() + { + if (GameManager.Instance.Assets.RegisteredResourceLocators.Any(x => x.Keys.Contains("resource_units"))) + { + GameManager.Instance.Assets.LoadByLabel("resource_units", RegisterUnits, + delegate(IList assetLocations) + { + if (assetLocations != null) + { + Addressables.Release(assetLocations); + } + }); + } + else + { + Logging.LogInfo("No custom resource units were defined"); + } + + PatchManager.Instance.AddComponent(); + } + + + private static void RegisterUnits(TextAsset textAsset) + { + var dict = JObject.Parse(textAsset.text); + foreach (var value in dict) + { + if (value.Value is not { Type: JTokenType.String }) continue; + ResourceUnits[value.Key] = value.Value.Value()!; + } + } + } +} \ No newline at end of file diff --git a/Runtime/PatchManager.Resources/ResourcesModule.cs.meta b/Runtime/PatchManager.Resources/ResourcesModule.cs.meta new file mode 100644 index 0000000..f705d5f --- /dev/null +++ b/Runtime/PatchManager.Resources/ResourcesModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27fda0a63f70d1a42bdeacbaaeec3e08 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/PatchManager.Resources/Rulesets.meta b/Runtime/PatchManager.Resources/Rulesets.meta new file mode 100644 index 0000000..ca641ef --- /dev/null +++ b/Runtime/PatchManager.Resources/Rulesets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b9e847ee6abb2d4890963c139d35f51 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/PatchManager.Resources/Rulesets/ResourceRuleset.cs b/Runtime/PatchManager.Resources/Rulesets/ResourceRuleset.cs new file mode 100644 index 0000000..4a83f71 --- /dev/null +++ b/Runtime/PatchManager.Resources/Rulesets/ResourceRuleset.cs @@ -0,0 +1,55 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.Resources.Selectables; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; + +namespace PatchManager.Resources.Rulesets +{ + /// + /// A patcher ruleset meant for adapting/creating resource definitions + /// + [PatcherRuleset("resources", "resources")] + public class ResourceRuleset : IPatcherRuleSet + { + /// + public bool Matches(string label) => label == "resources"; + + /// + public ISelectable ConvertToSelectable(string type, string name, string jsonData) + { + var obj = JObject.Parse(jsonData); + if (obj.ContainsKey("isRecipe") && obj["isRecipe"]!.Value()) + { + return new RecipeSelectable(jsonData); + } + return new ResourceSelectable(jsonData); + } + + /// + public INewAsset CreateNew(List dataValues) + { + var isRecipe = false; + if (dataValues.Count == 2) + { + isRecipe = dataValues[1].Truthy; + } + + if (isRecipe) + { + var value = + $"{{\n \"version\": 0.1,\n \"useExternal\": false,\n \"isRecipe\": true,\n \"recipeData\": {{\n \"name\": \"{dataValues[0].String}\",\n \"displayNameKey\": \"Resource/DisplayName/Unknown\",\n \"abbreviationKey\": \"Resource/Abbreviation/UK\",\n \"resourceIconAssetAddress\": \"\",\n \"vfxFuelType\": \"NoFuel\",\n \"ingredients\": []\n }} \n}}"; + + return new NewGenericAsset("resources", dataValues[0].String, new RecipeSelectable(value)); + } + else + { + var value = + $"{{\n \"version\": 0.1,\n \"useExternal\": false,\n \"data\": {{\n \"name\": \"{dataValues[0].String}\",\n \"displayNameKey\": \"Resource/DisplayName/Unknown\",\n \"abbreviationKey\": \"Resource/Abbreviation/UK\",\n \"isTweakable\": true,\n \"isVisible\": true,\n \"massPerUnit\": 0,\n \"volumePerUnit\": 0,\n \"specificHeatCapacityPerUnit\": 0,\n \"flowMode\": 0,\n \"transferMode\": 0,\n \"costPerUnit\": 0,\n\t\"NonStageable\": false,\n \"resourceIconAssetAddress\": \"\",\n \"vfxFuelType\": \"NoFuel\" \n }} \n}}"; + return new NewGenericAsset("resources", dataValues[0].String, new ResourceSelectable(value)); + } + } + } +} \ No newline at end of file diff --git a/Runtime/PatchManager.Resources/Rulesets/ResourceRuleset.cs.meta b/Runtime/PatchManager.Resources/Rulesets/ResourceRuleset.cs.meta new file mode 100644 index 0000000..9c4b3f1 --- /dev/null +++ b/Runtime/PatchManager.Resources/Rulesets/ResourceRuleset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f64275fe6c1efe4fbce63df42db0e63 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/PatchManager.Resources/Rulesets/ResourceUnitRuleset.cs b/Runtime/PatchManager.Resources/Rulesets/ResourceUnitRuleset.cs new file mode 100644 index 0000000..7d112f9 --- /dev/null +++ b/Runtime/PatchManager.Resources/Rulesets/ResourceUnitRuleset.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; +using PatchManager.SassyPatching.Selectables; + +namespace PatchManager.Resources.Rulesets +{ + /// + /// Implements the resource units ruleset from https://github.com/KSP2Community/CommunityResources + /// + [PatcherRuleset("resource_units","resource_units")] + public class ResourceUnitRuleset : IPatcherRuleSet + { + public bool Matches(string label) => label == "resource_units"; + + public ISelectable ConvertToSelectable(string type, string name, string jsonData) => new JTokenSelectable(() => + { + }, JObject.Parse(jsonData), name, type); + + private static int _globallyIncrementingId = 0; + + public INewAsset CreateNew(List dataValues) + { + var id = _globallyIncrementingId++; + return new NewGenericAsset("resource_units", $"resource_unit_definition_{id}", new JTokenSelectable( + () => { }, new JObject(), $"resource_unit_definition_{id}", "resource_units")); + } + } +} \ No newline at end of file diff --git a/Runtime/PatchManager.Resources/Rulesets/ResourceUnitRuleset.cs.meta b/Runtime/PatchManager.Resources/Rulesets/ResourceUnitRuleset.cs.meta new file mode 100644 index 0000000..fd793ba --- /dev/null +++ b/Runtime/PatchManager.Resources/Rulesets/ResourceUnitRuleset.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e7dcffa84a54436ca9e3666062f0e39d +timeCreated: 1739535998 \ No newline at end of file diff --git a/Runtime/PatchManager.Resources/Selectables.meta b/Runtime/PatchManager.Resources/Selectables.meta new file mode 100644 index 0000000..e0a29d2 --- /dev/null +++ b/Runtime/PatchManager.Resources/Selectables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 38060e8b3e499e14db14abcfd2f0286f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/PatchManager.Resources/Selectables/RecipeSelectable.cs b/Runtime/PatchManager.Resources/Selectables/RecipeSelectable.cs new file mode 100644 index 0000000..5465f44 --- /dev/null +++ b/Runtime/PatchManager.Resources/Selectables/RecipeSelectable.cs @@ -0,0 +1,118 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Modifiables; +using PatchManager.SassyPatching.Selectables; + +namespace PatchManager.Resources.Selectables +{ + /// + /// Represents a selectable for the selection and transformation of recipe data + /// + public sealed class RecipeSelectable : BaseSelectable + { + + private bool _modified; + private bool _deleted; + private readonly string _originalData; + internal readonly JObject JObject; + internal readonly JArray Ingredients; + internal readonly Dictionary IngredientIndices; + + /// + /// Marks this resource selectable as having been modified any level down + /// + public void SetModified() + { + _modified = true; + } + + /// + /// Marks this resource as goneso + /// + public void SetDeleted() + { + SetModified(); + _deleted = true; + } + + internal RecipeSelectable(string data) + { + _originalData = data; + JObject = JObject.Parse(data); + IngredientIndices = new Dictionary(); + Classes = new List { "recipe" }; + Children = new List(); + var resourceData = JObject["recipeData"]; + Name = (string)resourceData?["name"]; + Ingredients = (JArray)resourceData?["ingredients"]; + ElementType = "recipe"; + var index = 0; + foreach (var ingredient in Ingredients!) + { + IngredientIndices[ingredient["name"]!.Value()] = index++; + Classes.Add(ingredient["name"]!.Value()); + Children.Add( + new JTokenSelectable(SetModified, ingredient, tok => tok["name"].Value(), "ingredient")); + } + } + + /// + public override List Children { get; } + + /// + public override string Name { get; } + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + classValue = null; + if (@class == "recipe") + { + classValue = DataValue.FromJToken(JObject["recipeData"]); + return true; + } + if (IngredientIndices.TryGetValue(@class, out var index)) + { + classValue = DataValue.FromJToken(Ingredients[index]); + return true; + } + + return false; + + } + + /// + public override string ElementType { get; } + + /// + public override bool IsSameAs(ISelectable other) => other is RecipeSelectable rs && rs.Name == Name; + + /// + public override IModifiable OpenModification() => new JTokenModifiable(JObject["recipeData"], SetModified); + + /// + public override ISelectable AddElement(string elementType) + { + var obj = new JObject + { + ["name"] = elementType, + ["unitsPerRecipeUnit"] = 0.00 + }; + var child = new JTokenSelectable(SetModified, obj, tok => tok["name"].Value(), "ingredient"); + Children.Add(child); + Ingredients.Add(obj); + return child; + } + + /// + public override string Serialize() => _modified ? _deleted ? "" : JObject.ToString() : _originalData; + + /// + public override DataValue GetValue() => OpenModification().Get(); + } +} \ No newline at end of file diff --git a/Runtime/PatchManager.Resources/Selectables/RecipeSelectable.cs.meta b/Runtime/PatchManager.Resources/Selectables/RecipeSelectable.cs.meta new file mode 100644 index 0000000..c2ac6ed --- /dev/null +++ b/Runtime/PatchManager.Resources/Selectables/RecipeSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 678f46659d711c544ae83b5d87a1135c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/PatchManager.Resources/Selectables/ResourceSelectable.cs b/Runtime/PatchManager.Resources/Selectables/ResourceSelectable.cs new file mode 100644 index 0000000..45d37a9 --- /dev/null +++ b/Runtime/PatchManager.Resources/Selectables/ResourceSelectable.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Modifiables; + +namespace PatchManager.Resources.Selectables +{ + /// + /// Represents a selectable for the selection and transformation of resource data + /// + public class ResourceSelectable : BaseSelectable + { + private bool _modified; + private bool _deleted; + + + /// + /// Marks this resource selectable as having been modified any level down + /// + public void SetModified() + { + _modified = true; + } + + /// + /// Marks this resource as goneso + /// + public void SetDeleted() + { + SetModified(); + _deleted = true; + } + + private readonly string _originalData; + internal readonly JObject JObject; + + internal ResourceSelectable(string data) + { + _originalData = data; + JObject = JObject.Parse(data); + Classes = new() { "resource" }; + Children = new(); + var resourceData = JObject["data"]; + Name = (string)resourceData["name"]; + ElementType = "resource"; + } + + /// + public override List Children { get; } + + /// + public override string Name { get; } + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + classValue = null; + if (@class == "resource") + { + classValue = DataValue.FromJToken(JObject["data"]); + return true; + } + return false; + } + + /// + public override string ElementType { get; } + + /// + public override bool IsSameAs(ISelectable other) => other is ResourceSelectable rs && rs.Name == Name; + + /// + public override IModifiable OpenModification() => new JTokenModifiable(JObject["data"], SetModified); + + /// + public override ISelectable AddElement(string elementType) => throw new InvalidOperationException(); + + /// + public override string Serialize() => _modified ? _deleted ? "" : JObject.ToString() : _originalData; + + /// + public override DataValue GetValue() => OpenModification().Get(); + } +} \ No newline at end of file diff --git a/Runtime/PatchManager.Resources/Selectables/ResourceSelectable.cs.meta b/Runtime/PatchManager.Resources/Selectables/ResourceSelectable.cs.meta new file mode 100644 index 0000000..8cb3c67 --- /dev/null +++ b/Runtime/PatchManager.Resources/Selectables/ResourceSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f3b228f70edf30f459c07cd9756b25ac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/PatchManager.cs b/Runtime/PatchManager.cs new file mode 100644 index 0000000..4561000 --- /dev/null +++ b/Runtime/PatchManager.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using PatchManager.Core; +using PatchManager.Generic; +using PatchManager.Missions; +using PatchManager.Parts; +using PatchManager.Parts.Selectables; +using PatchManager.Resources; +using PatchManager.Science; +using PatchManager.Shared; +using PatchManager.Shared.Modules; +using Redux.ExtraModTypes; +using ReduxLib.Configuration; +using SpaceWarp.API.Mods; +using UnityEngine; +using UnityEngine.UIElements; +using ILogger = ReduxLib.Logging.ILogger; + +namespace PatchManager +{ + public class PatchManager : KerbalMod + { + internal static PatchManager Instance; + public void Awake() + { + // Let's register all our modules! + Instance = this; + ModuleManager.Register(typeof(CoreModule)); + ModuleManager.Register(typeof(GenericModule)); + ModuleManager.Register(typeof(MissionsModule)); + ModuleManager.Register(typeof(PartsModule)); + ModuleManager.Register(typeof(ResourcesModule)); + ModuleManager.Register(typeof(ScienceModule)); + Logging.Initialize(SWLogger); + foreach (var module in ModuleManager.Modules) + { + // We are going to use reduxes core configuration + module.BindConfiguration(SWConfiguration); + } + ModuleManager.InitAll(); + } + + public override void OnPreInitialized() + { + ModuleManager.PreLoadAll(); + } + + public override void OnInitialized() + { + ModuleManager.LoadAll(); + } + + public override void OnPostInitialized() + { + InitializePatchManagerDetailsFoldout(); + } + + private static void InitializePatchManagerDetailsFoldout() + { + VisualElement GeneratePatchManagerText() + { + var detailsContainer = new ScrollView(); + var str = "Loaded modules: "; + var toAdd = new List(); + foreach (var module in ModuleManager.Modules) + { + str += $"\n- {module.GetType().Name}"; + var details = module.GetDetails(); + if (details != null) + { + toAdd.Add(details); + } + } + + str += "\n"; + var loadedModules = new TextElement + { + text = str, + visible = true, + style = + { + display = DisplayStyle.Flex + } + }; + detailsContainer.Add(loadedModules); + foreach (var element in toAdd) + { + detailsContainer.Add(element); + } + + detailsContainer.visible = true; + detailsContainer.style.display = DisplayStyle.Flex; + return detailsContainer; + } + + SpaceWarp.UI.API.ModList.RegisterDetailsFoldoutGenerator("PatchManager", GeneratePatchManagerText); + } + } +} \ No newline at end of file diff --git a/Runtime/PatchManager.cs.meta b/Runtime/PatchManager.cs.meta new file mode 100644 index 0000000..9ab25a6 --- /dev/null +++ b/Runtime/PatchManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 37da4dec6401493ba6f5e9bf4dc14972 +timeCreated: 1739382527 \ No newline at end of file diff --git a/Runtime/Planets.meta b/Runtime/Planets.meta new file mode 100644 index 0000000..2ab5008 --- /dev/null +++ b/Runtime/Planets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3bd5e553aee95514790c6a5d0ca966a8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker.meta b/Runtime/Planets/Shoemaker.meta new file mode 100644 index 0000000..5e0cfa4 --- /dev/null +++ b/Runtime/Planets/Shoemaker.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7e5fbfcdf3b1764499ebfbb5ea0299ad +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager/Directory.Build.targets b/Runtime/Planets/Shoemaker/Directory.Build.targets similarity index 68% rename from src/PatchManager/Directory.Build.targets rename to Runtime/Planets/Shoemaker/Directory.Build.targets index 63c2730..90f6f7d 100644 --- a/src/PatchManager/Directory.Build.targets +++ b/Runtime/Planets/Shoemaker/Directory.Build.targets @@ -1,11 +1,12 @@ - + + - nuget - mono /usr/local/bin/nuget.exe powershell pwsh + + @@ -15,7 +16,7 @@ - + - - - - - + - - @@ -51,7 +46,7 @@ - + @@ -68,7 +63,8 @@ - + + - - - - - - - - - - - - - - - - - - - + + - \ No newline at end of file + + diff --git a/Runtime/Planets/Shoemaker/Directory.Build.targets.meta b/Runtime/Planets/Shoemaker/Directory.Build.targets.meta new file mode 100644 index 0000000..bc69bbd --- /dev/null +++ b/Runtime/Planets/Shoemaker/Directory.Build.targets.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d48fcc87256931e4b9f4b65a94492091 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Modifiables.meta b/Runtime/Planets/Shoemaker/Modifiables.meta new file mode 100644 index 0000000..5ddc718 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Modifiables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d16c24effd80c8340bf5b36ae4cb1f6f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs b/Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs new file mode 100644 index 0000000..06964e4 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs @@ -0,0 +1,28 @@ +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Modifiables; +using Shoemaker.Selectables; + +namespace Shoemaker.Modifiables +{ + public class AtmosphereOverrideModifiable : JTokenModifiable + { + private AtmosphereOverrideSelectable _atmosphereOverrideSelectable; + + /// + /// Creates a new for the given . + /// + /// The selectable to modify. + public AtmosphereOverrideModifiable(AtmosphereOverrideSelectable selectable) : base(selectable.AtmosphereOverrideObject, selectable.SetModified) => _atmosphereOverrideSelectable = selectable; + + /// + public override void Set(DataValue dataValue) + { + if (dataValue.IsDeletion) + { + _atmosphereOverrideSelectable.SetDeleted(); + return; + } + base.Set(dataValue); + } + } +} \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs.meta b/Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs.meta new file mode 100644 index 0000000..246cd2e --- /dev/null +++ b/Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b8493a99118f5d642bc78277b421e90f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs b/Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs new file mode 100644 index 0000000..37d3ed5 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs @@ -0,0 +1,28 @@ +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Modifiables; +using Shoemaker.Selectables; + +namespace Shoemaker.Modifiables +{ + public class CelestialBodyModifiable : JTokenModifiable + { + private CelestialBodySelectable _celestialBodySelectable; + + /// + /// Creates a new for the given . + /// + /// The selectable to modify. + public CelestialBodyModifiable(CelestialBodySelectable selectable) : base(selectable.DataObject, selectable.SetModified) => _celestialBodySelectable = selectable; + + /// + public override void Set(DataValue dataValue) + { + if (dataValue.IsDeletion) + { + _celestialBodySelectable.SetDeleted(); + return; + } + base.Set(dataValue); + } + } +} \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs.meta b/Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs.meta new file mode 100644 index 0000000..e093a39 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fc0beafcc88ee24409d36a716bf4f006 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs b/Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs new file mode 100644 index 0000000..f6457e8 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs @@ -0,0 +1,28 @@ +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Modifiables; +using Shoemaker.Selectables; + +namespace Shoemaker.Modifiables +{ + public class GalaxyModifiable : JTokenModifiable + { + private GalaxySelectable _galaxySelectable; + + /// + /// Creates a new for the given . + /// + /// The selectable to modify. + public GalaxyModifiable(GalaxySelectable selectable) : base(selectable.GalaxyObject, selectable.SetModified) => _galaxySelectable = selectable; + + /// + public override void Set(DataValue dataValue) + { + if (dataValue.IsDeletion) + { + _galaxySelectable.SetDeleted(); + return; + } + base.Set(dataValue); + } + } +} \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs.meta b/Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs.meta new file mode 100644 index 0000000..a950bb0 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fdda9387f4caeb74eb2cdca951eb05dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs b/Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs new file mode 100644 index 0000000..037de0f --- /dev/null +++ b/Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs @@ -0,0 +1,28 @@ +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Modifiables; +using Shoemaker.Selectables; + +namespace Shoemaker.Modifiables +{ + public class VolumeCloudOverrideModifiable : JTokenModifiable + { + private readonly VolumeCloudSelectable _volumeCloudSelectable; + + /// + /// Creates a new for the given . + /// + /// The selectable to modify. + public VolumeCloudOverrideModifiable(VolumeCloudSelectable selectable) : base(selectable.VolumeCloudOverrideObject, selectable.SetModified) => _volumeCloudSelectable = selectable; + + /// + public override void Set(DataValue dataValue) + { + if (dataValue.IsDeletion) + { + _volumeCloudSelectable.SetDeleted(); + return; + } + base.Set(dataValue); + } + } +} \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs.meta b/Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs.meta new file mode 100644 index 0000000..5cf42ac --- /dev/null +++ b/Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: da9a67e1fe990344281261e63ee7ca2a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/OverrideManager.cs b/Runtime/Planets/Shoemaker/OverrideManager.cs new file mode 100644 index 0000000..eee8684 --- /dev/null +++ b/Runtime/Planets/Shoemaker/OverrideManager.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using KSP.VolumeCloud; +using Shoemaker.Overrides; + +namespace Shoemaker +{ + [PublicAPI] + public static class OverrideManager + { + public static Dictionary AtmosphereOverrides = new(); + public static Dictionary Scales = new(); + public static Dictionary VolumeCloudOverrides = new(); + + } +} + diff --git a/Runtime/Planets/Shoemaker/OverrideManager.cs.meta b/Runtime/Planets/Shoemaker/OverrideManager.cs.meta new file mode 100644 index 0000000..7f82285 --- /dev/null +++ b/Runtime/Planets/Shoemaker/OverrideManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb9db04c88d10c544832ef17aeb8c3f7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Overrides.meta b/Runtime/Planets/Shoemaker/Overrides.meta new file mode 100644 index 0000000..5df65e6 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Overrides.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 853b57e5746286842a82e957df725cee +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs b/Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs new file mode 100644 index 0000000..05a94ca --- /dev/null +++ b/Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs @@ -0,0 +1,87 @@ +using JetBrains.Annotations; +using KSP.Game; +using KSP.Rendering; +using UnityEngine; + +namespace Shoemaker.Overrides +{ + [PublicAPI] + [UsedImplicitly] + public struct AtmosphereOverride : IOverride + { + public string PlanetName; + public bool? IsGasGiant; + public Vector2? Exposure; + public float? SunAngleRadius; + public float? SunZenithAngle; + public Vector3? SolarIrradiance; + public float? SunDirectionExposureModifier; + public float? TransmittanceTint; + public float? NoonColorStrength; + public float? SunsetColorStrength; + public float? ColorTransitionScale; + public float? BottomRadius; + public float? AtmosphereHeight; + public Color? GroundAlbedo; + public Vector3? RayleighScattering; + public float? RayleighScatteringScale; + public float? RayleighExponentialDistribution; + public Vector3? MieScattering; + public float? MieScatteringScale; + public float? MieAnistropy; + public float? MieExponentialDistribution; + public float? AbsorptionScale; + public Vector3? Absorption; + public float? AbsorptionMaxDensity; + public Vector2? AbsorptionHeightMinMax; + [CanBeNull] public string TransmittanceTexture; + [CanBeNull] public string IrradianceTexture; + [CanBeNull] public string ScatteringTexture; + + public void ApplyTo(AtmosphereModel atmosphereModel) + { + if (IsGasGiant.HasValue) atmosphereModel.IsGasGiant = IsGasGiant.Value; + if (Exposure.HasValue) atmosphereModel.Exposure = Exposure.Value; + if (SunAngleRadius.HasValue) atmosphereModel.SunAngleRadius = SunAngleRadius.Value; + if (SunZenithAngle.HasValue) atmosphereModel.SunZenithAngle = SunZenithAngle.Value; + if (SolarIrradiance.HasValue) atmosphereModel.SolarIrradiance = SolarIrradiance.Value; + if (SunDirectionExposureModifier.HasValue) + atmosphereModel.SunDirectionExposureModifier = SunDirectionExposureModifier.Value; + if (TransmittanceTint.HasValue) atmosphereModel.TransmittanceTint = TransmittanceTint.Value; + if (NoonColorStrength.HasValue) atmosphereModel.NoonColorStrengh = NoonColorStrength.Value; + if (SunsetColorStrength.HasValue) atmosphereModel.SunsetColorStrengh = SunsetColorStrength.Value; + if (ColorTransitionScale.HasValue) atmosphereModel.ColorTransitionScale = ColorTransitionScale.Value; + if (BottomRadius.HasValue) atmosphereModel.BottomRadius = BottomRadius.Value; + if (AtmosphereHeight.HasValue) atmosphereModel.AtmosphereHeight = AtmosphereHeight.Value; + if (GroundAlbedo.HasValue) atmosphereModel.GroundAlbedo = GroundAlbedo.Value; + if (RayleighScattering.HasValue) atmosphereModel.RayleighScattering = RayleighScattering.Value; + if (RayleighScatteringScale.HasValue) atmosphereModel.RayleighScatteringScale = RayleighScatteringScale.Value; + if (RayleighExponentialDistribution.HasValue) + atmosphereModel.RayleighExponentialDistribution = RayleighExponentialDistribution.Value; + if (MieScattering.HasValue) atmosphereModel.MieScattering = MieScattering.Value; + if (MieScatteringScale.HasValue) atmosphereModel.MieScatteringScale = MieScatteringScale.Value; + if (MieAnistropy.HasValue) atmosphereModel.MieAnisotropy = MieAnistropy.Value; + if (MieExponentialDistribution.HasValue) + atmosphereModel.MieExponentialDistribution = MieExponentialDistribution.Value; + if (AbsorptionScale.HasValue) atmosphereModel.AbsorptionScale = AbsorptionScale.Value; + if (Absorption.HasValue) atmosphereModel.Absorption = Absorption.Value; + if (AbsorptionHeightMinMax.HasValue) atmosphereModel.AbsorptionHeightMinMax = AbsorptionHeightMinMax.Value; + if (!string.IsNullOrEmpty(TransmittanceTexture)) + { + GameManager.Instance.Assets.TryLoad(TransmittanceTexture, + asset => atmosphereModel.TransmittanceTexture = asset); + } + if (!string.IsNullOrEmpty(IrradianceTexture)) + { + GameManager.Instance.Assets.TryLoad(IrradianceTexture, + asset => atmosphereModel.IrradianceTexture = asset); + } + if (!string.IsNullOrEmpty(ScatteringTexture)) + { + GameManager.Instance.Assets.TryLoad(ScatteringTexture, + asset => atmosphereModel.ScatteringTexture = asset); + } + } + } +} + diff --git a/Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs.meta b/Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs.meta new file mode 100644 index 0000000..45cd5e3 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3f528aba5c9895940aae4d8db841c82b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs b/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs new file mode 100644 index 0000000..3a4253f --- /dev/null +++ b/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs @@ -0,0 +1,48 @@ +// ReSharper disable InconsistentNaming +// ReSharper disable IdentifierTypo + +using JetBrains.Annotations; +using KSP.VolumeCloud; +using UnityEngine; + +namespace Shoemaker.Overrides +{ + [PublicAPI] + public class CloudsDataOverride : IOverride + { + public string layerName; + public bool? isEnable; + public bool? castShadow; + public float? bakeCloudMipmap; + public float? currentBakedCloudMipMap; + public VolumeCloudConfiguration.CloudsLayerType? cloudsType; + public Vector2? cloudHeightRange; + public float? bakedCloudHeight; + public Vector3? cloudsLayerRotate; + public bool? enableWind; + public Vector2? windDirection; + public float? movementSpeed; + public float? evolveSpeed; + public float? topOffset; + public bool? isFold; + + public void ApplyTo(VolumeCloudConfiguration.CloudsData obj) + { + isEnable.Apply(value => obj.isEnable = value ?? false); + castShadow.Apply(value => obj.castShadow = value ?? false); + bakeCloudMipmap.Apply(value => obj.bakeCloudMipmap = value ?? 0); + currentBakedCloudMipMap.Apply(value => obj.currentBakedCloudMipmap = value ?? 0); + cloudsType.Apply(value => obj.cloudsType = value ?? VolumeCloudConfiguration.CloudsLayerType.Cumulus); + cloudHeightRange.Apply(value => obj.cloudHeightRange = value ?? Vector2.zero); + bakedCloudHeight.Apply(value => obj.bakedCloudHeight = value ?? 0); + cloudsLayerRotate.Apply(value => obj.cloudsLayerRotate = value ?? Vector3.zero); + enableWind.Apply(value => obj.enableWind = value ?? false); + windDirection.Apply(value => obj.windDirection = value ?? Vector2.zero); + movementSpeed.Apply(value => obj.movementSpeed = value ?? 0f); + evolveSpeed.Apply(value => obj.evolveSpeed = value ?? 0f); + topOffset.Apply(value => obj.topOffset = value ?? 0f); + isFold.Apply(value => obj.isFold = value ?? false); + } + } +} + diff --git a/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs.meta b/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs.meta new file mode 100644 index 0000000..2a49605 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a99547e02aad84f4db48bcdd725d3285 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Overrides/IOverride.cs b/Runtime/Planets/Shoemaker/Overrides/IOverride.cs new file mode 100644 index 0000000..1cc10a5 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Overrides/IOverride.cs @@ -0,0 +1,7 @@ +namespace Shoemaker.Overrides +{ + public interface IOverride where T : class + { + public void ApplyTo(T obj); + } +} \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Overrides/IOverride.cs.meta b/Runtime/Planets/Shoemaker/Overrides/IOverride.cs.meta new file mode 100644 index 0000000..dc09456 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Overrides/IOverride.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 65f3e4eaadb8a054fb4e16acc75ec496 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs b/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs new file mode 100644 index 0000000..3646ea8 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs @@ -0,0 +1,158 @@ +using System.Collections.Generic; +using System.Linq; +using JetBrains.Annotations; +using KSP.VolumeCloud; +using UnityEngine; +using static Shoemaker.Utility.Extensions; + +// ReSharper disable InconsistentNaming +// ReSharper disable IdentifierTypo + +namespace Shoemaker.Overrides +{ + [PublicAPI] + public class VolumeCloudConfigurationOverride : IOverride + { + public string bodyName; + public bool? exclusiveLayer; + public Vector3? CloudsRotateAll; + public float? planetRadius; + public bool? enableColorMap; + public bool? enableVerticalColor; + public float? colorMapIntensity; + public float? verticalColorIntensity; + // [CanBeNull] public Gradient ColorVertical; + public float? overallSize; + public Vector2? vortexCloudHeightRange; + // todo: lenticular list + public List cumulusList = new List(); + // todo: cumulus list + // todo: cumulus index + public float? cloudCoverageModifier; + public float? detailVariationRange; + public bool? enableShadows; + public bool? enableLayerShadows; + public float? volumetricShadowDensity; + public float? volumetricShadowLodBias; + public float? volumetricShadowDistance; + public float? shadowOpacity; + public float? shadowMapStrength; + public float? layerShadowDensity; + public Color? ambientColor; + public bool? EnableCloudGI; + public float? cloudGIIntensity; + public float? cloudGITint; + public float? lightPenetrateDistance; + public float? multiScatteringScattering; + public float? extinctionByLightPosition; + public float? opticsDistanceScale; + public float? silverSpreadG; + public float? bloomStrengthG; + public float? silverSpreadUnderCloudG; + public float? bloomStrengthUnderCloudG; + public float? silverSpread; + public float? bloomStrength; + public float? silverSpreadUnderCloud; + public float? bloomStrengthUnderCloud; + public float? ambientScale; + public float? scatteringScale; + public float? cloudsDensityScale; + public bool? enableGodray; + public float? godrayIntensity; + public float? godrayVisibleDistance; + public float? godrayStepSize; + public float? sampleLightStepSize; + public float? sampleLightStepCount; + public Vector2? cloudDensityRangeEmitGodray; + public float? godrayAttenuation; + public float? godrayFadeHeight; + public float? godrayBlurSize; + public bool? IsBlurGodray; + public float? antiBandingAmplify; + public bool? useScaleCloudsOnly; + public float? raymarchStepSize; + public bool? increaseRaymarchStepByDistance; + public float? distanceRatio; + public float? maxRaymarchStepSize; + public bool? cullingEdgeClouds; + public float? cullingStrength; + public bool? autoMipmap; + public float? scaleCloudMaskNormalTileRate; + public float? cascadedResolutionRange; + public float? mipmapScale; + public bool? enableFadeout; + public float? startFadeoutHeight; + public float? endFadeoutHeight; + + public void ApplyTo(VolumeCloudConfiguration obj) + { + exclusiveLayer.Apply(ref obj.exclusiveLayer); + CloudsRotateAll.Apply(ref obj.CloudsRotateAll); + planetRadius.Apply(ref obj.planetRadius); + enableColorMap.Apply(ref obj.enableColorMap); + enableVerticalColor.Apply(ref obj.enableVerticalColor); + colorMapIntensity.Apply(ref obj.colorMapIntensity); + verticalColorIntensity.Apply(ref obj.verticalColorIntensity); + overallSize.Apply(ref obj.overallSize); + vortexCloudHeightRange.Apply(ref obj.vortexCloudHeightRange); + foreach (var item in cumulusList) + if (obj.cumulusList.FirstOrDefault(x => x.layerName == item.layerName) is {} first) item.ApplyTo(first); + cloudCoverageModifier.Apply(ref obj.cloudCoverageModifier); + detailVariationRange.Apply(ref obj.detailVariationRange); + enableShadows.Apply(ref obj.enableShadows); + enableLayerShadows.Apply(ref obj.enableLayerShadows); + volumetricShadowDensity.Apply(ref obj.volumetricShadowDensity); + volumetricShadowLodBias.Apply(ref obj.volumetricShadowLodBias); + volumetricShadowDistance.Apply(ref obj.volumetricShadowDistance); + shadowOpacity.Apply(ref obj.shadowOpacity); + shadowMapStrength.Apply(ref obj.shadowMapStrength); + layerShadowDensity.Apply(ref obj.layerShadowDensity); + ambientColor.Apply(ref obj.ambientColor); + EnableCloudGI.Apply(ref obj.EnableCloudGI); + cloudGIIntensity.Apply(ref obj.cloudGIIntensity); + cloudGITint.Apply(ref obj.cloudGITint); + lightPenetrateDistance.Apply(ref obj.lightPenetrateDistance); + multiScatteringScattering.Apply(ref obj.multiScatteringScattering); + extinctionByLightPosition.Apply(ref obj.extinctionByLightPosition); + opticsDistanceScale.Apply(ref obj.opticsDistanceScale); + silverSpreadG.Apply(ref obj.silverSpreadG); + bloomStrengthG.Apply(ref obj.bloomStrengthG); + silverSpreadUnderCloudG.Apply(ref obj.silverSpreadUnderCloudG); + bloomStrengthUnderCloudG.Apply(ref obj.bloomStrengthUnderCloudG); + silverSpread.Apply(ref obj.silverSpread); + bloomStrength.Apply(ref obj.bloomStrength); + silverSpreadUnderCloud.Apply(ref obj.silverSpreadUnderCloud); + bloomStrengthUnderCloud.Apply(ref obj.bloomStrengthUnderCloud); + ambientScale.Apply(ref obj.ambinetScale); + scatteringScale.Apply(ref obj.scatteringScale); + cloudsDensityScale.Apply(ref obj.cloudsDensityScale); + enableGodray.Apply(ref obj.enableGodray); + godrayIntensity.Apply(ref obj.godrayIntensity); + godrayVisibleDistance.Apply(ref obj.godrayVisableDistance); + godrayStepSize.Apply(ref obj.godrayStepSize); + sampleLightStepSize.Apply(ref obj.sampleLightStepSize); + sampleLightStepCount.Apply(ref obj.sampleLightStepCount); + cloudDensityRangeEmitGodray.Apply(ref obj.cloudDensityRangeEmitGodray); + godrayAttenuation.Apply(ref obj.godrayAttenuation); + godrayFadeHeight.Apply(ref obj.godrayFadeHeight); + godrayBlurSize.Apply(ref obj.godrayBlurSize); + IsBlurGodray.Apply(ref obj.IsBlurGodray); + antiBandingAmplify.Apply(ref obj.antiBandingAmplify); + useScaleCloudsOnly.Apply(ref obj.useScaleCloudsOnly); + raymarchStepSize.Apply(ref obj.raymarchStepSize); + increaseRaymarchStepByDistance.Apply(ref obj.increaceRaymarchStepByDistance); + distanceRatio.Apply(ref obj.distanceRatio); + maxRaymarchStepSize.Apply(ref obj.maxRaymarchStepSize); + cullingEdgeClouds.Apply(ref obj.cullingEdgeClouds); + cullingStrength.Apply(ref obj.cullingStrength); + autoMipmap.Apply(ref obj.autoMipmap); + scaleCloudMaskNormalTileRate.Apply(ref obj.scaleCloudMaskNormalTileRate); + cascadedResolutionRange.Apply(ref obj.cascadedResolutionRange); + mipmapScale.Apply(ref obj.mipmapScale); + enableFadeout.Apply(ref obj.enableFadeout); + startFadeoutHeight.Apply(ref obj.startFadeoutHeight); + endFadeoutHeight.Apply(ref obj.endFadeoutHeight); + } + } +} + diff --git a/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs.meta b/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs.meta new file mode 100644 index 0000000..17e1239 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0ab89b9370f0fdd48833a9ae261002e3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Patches.meta b/Runtime/Planets/Shoemaker/Patches.meta new file mode 100644 index 0000000..a7257fc --- /dev/null +++ b/Runtime/Planets/Shoemaker/Patches.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 932a8a9f89faca54f9b87d30ef3b1a9c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs b/Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs new file mode 100644 index 0000000..bc64f61 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs @@ -0,0 +1,35 @@ +/*using HarmonyLib; +using KSP.Game; +using KSP.Rendering; +using KSP.Rendering.Planets; +using Shoemaker; + +namespace Shoemaker.Patches +{ + //[HarmonyPatch(typeof(AtmosphereScatterManager))] + internal static class AtmosphereScatterManagerPatches + { + // [HarmonyPatch(nameof(AtmosphereScatterManager.OnAtmosphereModelLoaded))] + // [HarmonyPrefix] + internal static void OnAtmosphereModelLoaded(AtmosphereScatterManager __instance, AtmosphereModel model) + { + if (model == null) + return; + // LogInfo($"The atmosphere model for {model.PlanetName} has been loaded"); + // LogInfo($"Bottom radius: {model.BottomRadius} km"); + // LogInfo($"Height: {model.AtmosphereHeight} km"); + // LogInfo($"Absorption Height min-max: {model.AbsorptionHeightMinMax.x} - {model.AbsorptionHeightMinMax.y}"); + if (OverrideManager.AtmosphereOverrides.TryGetValue(model.PlanetName, out var @override)) + { + @override.ApplyTo(model); + // LogInfo($"Applied override to atmosphere for {model.PlanetName}: "); + // LogInfo($"Bottom radius: {model.BottomRadius} km"); + // LogInfo($"Height: {model.AtmosphereHeight} km"); + // LogInfo($"Absorption Height Min max: {model.AbsorptionHeightMinMax.x} - {model.AbsorptionHeightMinMax.y}"); + } + } + } +} + +*/ +// since we aren't locked to the confines of Harmony Patching we can just add these changes already \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs.meta b/Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs.meta new file mode 100644 index 0000000..099c171 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ec9e8c3237ae58a4bab84e398a6cc540 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs b/Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs new file mode 100644 index 0000000..732d7d7 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs @@ -0,0 +1,61 @@ +/*//using HarmonyLib; +using KSP; +using KSP.Game; +using KSP.Sim.impl; +using UnityEngine; + +namespace Shoemaker.Patches +{ + [HarmonyPatch(typeof(CelestialBodyBehavior))] + internal static class CelestialBodyBehaviourPatches + { + [HarmonyPatch(nameof(CelestialBodyBehavior.OnScaledSpaceViewInstantiated))] + [HarmonyPrefix] + internal static void MergeData(CelestialBodyBehavior __instance, GameObject instance) + { + + } + + [HarmonyPatch(nameof(CelestialBodyBehavior.OnLocalSpaceViewInstantiated))] + [HarmonyPrefix] + internal static void LogStuff(CelestialBodyBehavior __instance, GameObject obj) + { + LogInfo( + $"Following info is from the local space load of {__instance.CelestialBodyData.Data.bodyName}"); + LogInfo($"The celestial body has a radius of {__instance.CelestialBodyData.Data.radius}"); + LogInfo("The local space object has the following components:\n"); + foreach (var component in obj.GetComponents(typeof(UnityObject))) + { + LogInfo($"- {component.GetType()}"); + } + + // LogInfo($"The local space has the following prefabs\n"); + // if (obj.TryGetComponent(out NestedPrefabSpawner nestedPrefabSpawner)) + // { + // foreach (var prefab in nestedPrefabSpawner.Prefabs) + // { + // LogInfo($"- {prefab.PrefabAssetReference.AssetGUID}"); + // if (prefab.tgtTransform != null) + // { + // LogInfo($"\t- {prefab.tgtTransform.name}"); + // var operation = prefab.PrefabAssetReference.InstantiateAsync(); + // operation.Completed += x => + // { + // LogInfo($"From previous async handle for {prefab.PrefabAssetReference.AssetGUID}"); + // var surfaceObject = x.Result.GetComponent(); + // LogInfo($"Latitude - {surfaceObject.Latitude}"); + // LogInfo($"Longitude - {surfaceObject.Longitude}"); + // LogInfo($"Radial Offset - {surfaceObject.RadialOffset}"); + // LogInfo($"Degrees around radial normal - {surfaceObject.DegreesAroundRadialNormal}"); + // x.Result.DestroyGameObject(); + // }; + // } + // } + // } + // var scale = OverrideManager.Scales[__instance.CelestialBodyData.Data.bodyName]; + + // obj.transform.localScale *= (float)scale; + } + + } +}*/ \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs.meta b/Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs.meta new file mode 100644 index 0000000..05f9100 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9457beb8a75ad4e41b5f61d51ee72ec3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs b/Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs new file mode 100644 index 0000000..d7ad8d7 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Reflection.Emit; +/*using HarmonyLib; +using KSP.VolumeCloud; +using UnityEngine.ResourceManagement.AsyncOperations; + +namespace Shoemaker.Patches +{ + public static class CloudRenderHelperPatches + { + // [HarmonyPatch(typeof(CloudRenderHelper))] + // [HarmonyPatch(nameof(CloudRenderHelper.LoadingConfigCompleted))] + // [HarmonyTranspiler] + // public static IEnumerable ModifyFunction(IEnumerable instructions) + // { + // yield return new CodeInstruction(OpCodes.Ldarg_1); + // yield return new CodeInstruction(OpCodes.Call,typeof(CloudRenderHelper).GetMethod(nameof(UpdateConfiguration),BindingFlags.Public | BindingFlags.Static)); + // foreach (var instruction in instructions) + // { + // yield return instruction; + // } + // } + + public static void UpdateConfiguration(AsyncOperationHandle configurationHandle) + { + if (configurationHandle.Status != AsyncOperationStatus.Succeeded) return; + var bodyName = configurationHandle.Result.bodyName; + if (!OverrideManager.VolumeCloudOverrides.TryGetValue(bodyName.ToLowerInvariant(), + out var volumeCloudConfigurationOverride)) return; + // LogInfo($"Found a configuration override for {bodyName}"); + volumeCloudConfigurationOverride.ApplyTo(configurationHandle.Result); + } + } +}*/ + diff --git a/Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs.meta b/Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs.meta new file mode 100644 index 0000000..1df8b04 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c857f7336fe9b9644a8bb0260e782a82 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs b/Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs new file mode 100644 index 0000000..0f8ba09 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs @@ -0,0 +1,20 @@ +// HarmonyLib; +//using KSP; +//using KSP.Game; +//using KSP.Rendering; +//using UnityEngine; + +//namespace Shoemaker.Patches +//{ + //[HarmonyPatch(typeof(ScaledCloudDataModelComponent))] +// internal static class ScaledCloudDataModelComponentPatches +/// { + // [HarmonyPatch(nameof(ScaledCloudDataModelComponent.Initialize))] + // [HarmonyPrefix] + // public static void UpdateCoreCelestialBodyData(ScaledCloudDataModelComponent __instance) + // { + + // } +// } +//} + diff --git a/Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs.meta b/Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs.meta new file mode 100644 index 0000000..0c5d4e6 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e3c14f71403e67d468003ed02fd6f998 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/PlanetsModule.cs b/Runtime/Planets/Shoemaker/PlanetsModule.cs new file mode 100644 index 0000000..3f4e8ce --- /dev/null +++ b/Runtime/Planets/Shoemaker/PlanetsModule.cs @@ -0,0 +1,38 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using KSP.Game; +using KSP.IO; +using Newtonsoft.Json; +using PatchManager.Shared.Modules; +using Shoemaker.Overrides; +using UnityEngine; +using UnityEngine.AddressableAssets; + +namespace Shoemaker +{ + public class PlanetsModule : BaseModule + { + private static void RegisterAtmosphereOverride(TextAsset atmosphereOverride) + { + var atmosphere = JsonConvert.DeserializeObject(atmosphereOverride.text); + OverrideManager.AtmosphereOverrides[atmosphere.PlanetName] = atmosphere; + } + + private static void RegisterVolumeCloudOverride(TextAsset volumeCloudOverride) + { + var volumeCloud = IOProvider.FromJson(volumeCloudOverride.text); + OverrideManager.VolumeCloudOverrides[volumeCloud.bodyName.ToLowerInvariant()] = volumeCloud; + } + + /// + /// Runs when the mod is first initialized. + /// + public override void Load() + { + GameManager.Instance.Assets.LoadByLabel("atmosphere_overrides", RegisterAtmosphereOverride, + delegate(IList assetLocations) { Addressables.Release(assetLocations); }); + GameManager.Instance.Assets.LoadByLabel("volume_cloud_overrides", RegisterVolumeCloudOverride, + delegate(IList assetLocations) { Addressables.Release(assetLocations); }); + } + } +} \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/PlanetsModule.cs.meta b/Runtime/Planets/Shoemaker/PlanetsModule.cs.meta new file mode 100644 index 0000000..4e5334c --- /dev/null +++ b/Runtime/Planets/Shoemaker/PlanetsModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 30b8274d97df87c4fa75a7a06125576c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Rulesets.meta b/Runtime/Planets/Shoemaker/Rulesets.meta new file mode 100644 index 0000000..8ac2f7a --- /dev/null +++ b/Runtime/Planets/Shoemaker/Rulesets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e60ec5f4ba39f2d4c8a30ca94cd399f3 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs b/Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs new file mode 100644 index 0000000..4ffd260 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; +using Shoemaker.Overrides; +using Shoemaker.Selectables; + +namespace Shoemaker.Rulesets +{ + [PatcherRuleset("atmosphere-override","atmosphere_overrides")] + public class AtmosphereOverrideRuleset : IPatcherRuleSet + { + public bool Matches(string label) => label == "atmosphere_overrides"; + + public ISelectable ConvertToSelectable(string type, string name, string jsonData) => + new AtmosphereOverrideSelectable(JObject.Parse(jsonData)); + + public INewAsset CreateNew(List dataValues) + { + var planetName = dataValues[0].String.ToLowerInvariant(); + var data = new AtmosphereOverride + { + PlanetName = planetName + }; + return new NewGenericAsset("atmosphere_overrides", $"atmosphere_override_{planetName}", + new AtmosphereOverrideSelectable(JObject.FromObject(data))); + } + } +} diff --git a/Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs.meta b/Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs.meta new file mode 100644 index 0000000..ce8d00a --- /dev/null +++ b/Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: baf197aecc8b90c4398c64fdec3051ee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs b/Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs new file mode 100644 index 0000000..a23ee4b --- /dev/null +++ b/Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using KSP.Sim.Definitions; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; +using Shoemaker.Selectables; + +namespace Shoemaker.Rulesets +{ + [PatcherRuleset("body","celestial_bodies")] + public class CelestialBodyRuleset : IPatcherRuleSet + { + public bool Matches(string label) => label == "celestial_bodies"; + + public ISelectable ConvertToSelectable(string type, string name, string jsonData) => + new CelestialBodySelectable(JObject.Parse(jsonData)); + + public INewAsset CreateNew(List dataValues) + { + var bodyName = dataValues[0].String; + var core = new CelestialBodyCore + { + version = CelestialBodyCore.CELESTIAL_BODY_SERIALIZATION_VERSION, + data = new CelestialBodyData + { + bodyName = bodyName + } + }; + return new NewGenericAsset("celestial_bodies", "bodyName", + new CelestialBodySelectable(JObject.FromObject(core))); + } + } +} \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs.meta b/Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs.meta new file mode 100644 index 0000000..418dc50 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 41c8895da2477ec448567e1fbbe52adb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs b/Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs new file mode 100644 index 0000000..1a627af --- /dev/null +++ b/Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs @@ -0,0 +1,42 @@ +using System.Collections.Generic; +using KSP.Sim; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; +using Shoemaker.Selectables; + +namespace Shoemaker.Rulesets +{ + /// + [PatcherRuleset("galaxy", "GalaxyDefinition_Default")] + public class GalaxyRuleset : IPatcherRuleSet + { + /// + public bool Matches(string label) => true; + + /// + public ISelectable ConvertToSelectable(string type, string name, string jsonData) + { + var obj = JObject.Parse(jsonData); + if (!obj.ContainsKey("Name") || !obj.ContainsKey("Version") || !obj.ContainsKey("CelestialBodies")) + return null; + return new GalaxySelectable(obj, type); + + } + /// + public INewAsset CreateNew(List dataValues) + { + var name = dataValues[0].String; + var version = dataValues.Count > 1 ? dataValues[1].String : "1.0.0"; + var def = new SerializedGalaxyDefinition + { + Name = name, + Version = version, + CelestialBodies = new List() + }; + return new NewGenericAsset(name, name, new GalaxySelectable(JObject.FromObject(def), name)); + } + } +} \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs.meta b/Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs.meta new file mode 100644 index 0000000..baf870f --- /dev/null +++ b/Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd770653019970b4fb19958ff71c9bc6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs b/Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs new file mode 100644 index 0000000..1edb6ca --- /dev/null +++ b/Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; +using Shoemaker.Overrides; +using Shoemaker.Selectables; + +namespace Shoemaker.Rulesets +{ + [PatcherRuleset("volume-cloud-override","volume_cloud_overrides")] + public class VolumeCloudOverrideRuleset : IPatcherRuleSet + { + public bool Matches(string label) => label == "volume_cloud_overrides"; + + public ISelectable ConvertToSelectable(string type, string name, string jsonData) => new VolumeCloudSelectable(JObject.Parse(jsonData)); + + public INewAsset CreateNew(List dataValues) + { + var planetName = dataValues[0].String.ToLowerInvariant(); + var data = new VolumeCloudConfigurationOverride + { + bodyName = planetName + }; + return new NewGenericAsset("volume_cloud_overrides", $"volume_cloud_override_{planetName}", + new VolumeCloudSelectable(JObject.FromObject(data))); + } + } +} \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs.meta b/Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs.meta new file mode 100644 index 0000000..2452e49 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4078d6870f426d84893ece9d0dd8a4ce +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Selectables.meta b/Runtime/Planets/Shoemaker/Selectables.meta new file mode 100644 index 0000000..4ff7a71 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Selectables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 60bc3af38d56af143b8c4fb7d5cf6a7a +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs b/Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs new file mode 100644 index 0000000..dc248d0 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using Shoemaker.Modifiables; + +namespace Shoemaker.Selectables +{ + public sealed class AtmosphereOverrideSelectable : BaseSelectable + { + #pragma warning disable CS0414 // Field is assigned but its value is never used + private bool _modified; + #pragma warning restore CS0414 // Field is assigned but its value is never used + private bool _deleted; + + /// + /// Marks this part selectable as having been modified any level down + /// + public void SetModified() + { + _modified = true; + } + + /// + /// Marks this part as goneso + /// + public void SetDeleted() + { + SetModified(); + _deleted = true; + } + + public readonly JObject AtmosphereOverrideObject; + + public AtmosphereOverrideSelectable(JObject atmosphereOverrideObject) + { + Children = new List(); + Classes = new List(); + ElementType = "atmosphere_override"; + AtmosphereOverrideObject = atmosphereOverrideObject; + Name = atmosphereOverrideObject["PlanetName"].Value(); + foreach (var (key, child) in atmosphereOverrideObject) + { + Classes.Add(key); + } + } + + /// + public override List Children { get; } + + /// + public override string Name { get; } + + /// + public override List Classes { get; } + + public override bool MatchesClass(string @class, out DataValue classValue) => + throw new Exception("Class capture selectors are not allowed on atmosphere overrides"); + + /// + public override bool IsSameAs(ISelectable other) => + other is AtmosphereOverrideSelectable atmosphereOverrideSelectable && atmosphereOverrideSelectable.AtmosphereOverrideObject == AtmosphereOverrideObject; + + /// + public override IModifiable OpenModification() => new AtmosphereOverrideModifiable(this); + + public override ISelectable AddElement(string elementType) => + throw new Exception("Adding elements to atmosphere overrides is not allowed"); + /// + public override string Serialize() => _deleted ? "" : AtmosphereOverrideObject.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(AtmosphereOverrideObject); + public override string ElementType { get; } + } +} + diff --git a/Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs.meta b/Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs.meta new file mode 100644 index 0000000..fd02921 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d07bb5f027a0e5141922cdc0c6981e97 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs b/Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs new file mode 100644 index 0000000..06816a4 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Selectables; +using Shoemaker.Modifiables; + +namespace Shoemaker.Selectables +{ + public sealed class CelestialBodySelectable : BaseSelectable + { + #pragma warning disable CS0414 // Field is assigned but its value is never used + private bool _modified; + #pragma warning restore CS0414 // Field is assigned but its value is never used + private bool _deleted; + + /// + /// Marks this part selectable as having been modified any level down + /// + public void SetModified() + { + _modified = true; + } + + /// + /// Marks this part as goneso + /// + public void SetDeleted() + { + SetModified(); + _deleted = true; + } + + public JObject CelestialBodyObject; + public JObject DataObject; + + public CelestialBodySelectable(JObject celestialBodyObject) + { + ElementType = "celestial_body"; + CelestialBodyObject = celestialBodyObject; + DataObject = (JObject)celestialBodyObject["data"]; + Classes = new List(); + Children = new List(); + foreach (var subToken in DataObject) + { + Classes.Add(subToken.Key); + Children.Add(new JTokenSelectable(SetModified,subToken.Value,subToken.Key)); + } + } + + public override bool MatchesClass(string @class, out DataValue classValue) + { + classValue = null; + if (!MatchesClass(@class)) + { + return false; + } + + classValue = DataValue.FromJToken(DataObject[@class]); + return true; + } + + public override bool IsSameAs(ISelectable other) => other is CelestialBodySelectable selectable && + selectable.CelestialBodyObject == CelestialBodyObject; + + public override IModifiable OpenModification() => new CelestialBodyModifiable(this); + + public override ISelectable AddElement(string elementType) + { + var obj = new JObject(); + DataObject[elementType] = obj; + var n = new JTokenSelectable(SetModified, obj, elementType); + Children.Add(n); + return n; + } + + public override string Serialize() => _deleted ? "" : CelestialBodyObject.ToString(); + + public override DataValue GetValue() => DataValue.FromJToken(DataObject); + + public override List Children { get; } + public override string Name => DataObject["bodyName"]!.Value(); + public override List Classes { get; } + public override string ElementType { get; } + } +} + diff --git a/Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs.meta b/Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs.meta new file mode 100644 index 0000000..e4867d2 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c8001b308deab4488a65a2b4052d46f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs b/Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs new file mode 100644 index 0000000..6ed2813 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs @@ -0,0 +1,122 @@ +using System.Collections.Generic; +using KSP.Sim; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Selectables; +using Shoemaker.Modifiables; + +namespace Shoemaker.Selectables +{ + public sealed class GalaxySelectable : BaseSelectable + { + #pragma warning disable CS0414 // Field is assigned but its value is never used + private bool _modified; + #pragma warning restore CS0414 // Field is assigned but its value is never used + private bool _deleted; + + /// + /// Marks this part selectable as having been modified any level down + /// + public void SetModified() + { + _modified = true; + } + + /// + /// Marks this part as goneso + /// + public void SetDeleted() + { + SetModified(); + _deleted = true; + } + + /// + /// This is the object that represents the galaxy definition + /// + public readonly JObject GalaxyObject; + /// + /// + /// + /// + /// + public GalaxySelectable(JObject galaxyObject, string elementType) + { + GalaxyObject = galaxyObject; + ElementType = elementType; + Name = galaxyObject["Name"].Value(); + Children = new List(); + Classes = new List(); + var bodies = (JArray)GalaxyObject["CelestialBodies"]; + foreach (var jToken in bodies) + { + var body = (JObject)jToken; + var name = body["GUID"]!.Value(); + Classes.Add(name); + Children.Add(new JTokenSelectable(SetModified, body, token => ((JObject)token).Value(), "planet")); + } + } + + /// + public override List Children { get; } + + /// + public override string Name { get; } + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + var bodies = (JArray)GalaxyObject["CelestialBodies"]; + foreach (var jToken in bodies!) + { + var body = (JObject)jToken; + var name = body["GUID"]!.Value(); + if (name != @class) + { + continue; + } + classValue = DataValue.FromJToken(body); + return true; + } + classValue = DataValue.Null; + return false; + } + + /// + public override bool IsSameAs(ISelectable other) => + other is GalaxySelectable galaxySelectable && galaxySelectable.GalaxyObject == GalaxyObject; + + /// + public override IModifiable OpenModification() => new GalaxyModifiable(this); + + /// + public override ISelectable AddElement(string elementType) + { + var obj = new SerializedCelestialBody + { + GUID = elementType, + OrbitProperties = new SerializedOrbitProperties(), + OrbiterProperties = new SerializedOribiterDefinition() + }; + var jToken = JObject.FromObject(obj); + Classes.Add(elementType); + var selectable = new JTokenSelectable(SetModified, jToken, token => ((JObject)token).Value(), "planet"); + Children.Add(selectable); + return selectable; + } + + /// + public override string Serialize() => _deleted ? "" : GalaxyObject.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(GalaxyObject); + + /// + public override string ElementType { get; } + } +} + diff --git a/Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs.meta b/Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs.meta new file mode 100644 index 0000000..d57fd3f --- /dev/null +++ b/Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 288eb2453d8b8b54596a6be096f22d74 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs b/Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs new file mode 100644 index 0000000..75c047c --- /dev/null +++ b/Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs @@ -0,0 +1,108 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Selectables; +using Shoemaker.Modifiables; +using Shoemaker.Overrides; + +namespace Shoemaker.Selectables +{ + public sealed class VolumeCloudSelectable : BaseSelectable + { + #pragma warning disable CS0414 // Field is assigned but its value is never used + private bool _modified; + #pragma warning restore CS0414 // Field is assigned but its value is never used + private bool _deleted; + + /// + /// Marks this part selectable as having been modified any level down/// + /// + public void SetModified() + { + _modified = true; + } + + /// + /// Marks this part as goneso + /// + public void SetDeleted() + { + SetModified(); + _deleted = true; + } + + public readonly JObject VolumeCloudOverrideObject; + + public VolumeCloudSelectable(JObject volumeCloudOverrideObject) + { + Children = new List(); + Classes = new List(); + ElementType = "volume_cloud_override"; + VolumeCloudOverrideObject = volumeCloudOverrideObject; + Name = volumeCloudOverrideObject["bodyName"].Value(); + foreach (var (key, child) in volumeCloudOverrideObject) + { + Classes.Add(key); + } + + foreach (var child in (JArray)volumeCloudOverrideObject["cumulusList"]) + { + var obj = (JObject)child; + var name = obj["layerName"]!.Value(); + Classes.Add(name); + Children.Add(new JTokenSelectable(SetModified, child, name, "cloud_data")); + } + } + + /// + public override List Children { get; } + + /// + public override string Name { get; } + + /// + public override List Classes { get; } + + public override bool MatchesClass(string @class, out DataValue classValue) + { + foreach (var value in (JArray)VolumeCloudOverrideObject["cumulusList"]!) + { + if (((JObject)value)["layerName"]!.Value() != @class) continue; + classValue = DataValue.FromJToken(value); + return true; + } + + classValue = DataValue.Null; + return false; + } + + /// + public override bool IsSameAs(ISelectable other) => + other is VolumeCloudSelectable volumeCloudSelectable && volumeCloudSelectable.VolumeCloudOverrideObject == VolumeCloudOverrideObject; + + /// + public override IModifiable OpenModification() => new VolumeCloudOverrideModifiable(this); + + public override ISelectable AddElement(string elementType) + { + var newLayer = new CloudsDataOverride + { + layerName = elementType + }; + var obj = JObject.FromObject(newLayer); + ((JArray)VolumeCloudOverrideObject["cumulusList"])!.Add(obj); + var selectable = new JTokenSelectable(SetModified, obj, elementType, "cloud_data"); + Children.Add(selectable); + Classes.Add(elementType); + return selectable; + } + /// + public override string Serialize() => _deleted ? "" : VolumeCloudOverrideObject.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(VolumeCloudOverrideObject); + public override string ElementType { get; } + } +} + diff --git a/Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs.meta b/Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs.meta new file mode 100644 index 0000000..de49019 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f2e1fb14766ae8648b6a7ce857baf144 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Shoemaker.csproj b/Runtime/Planets/Shoemaker/Shoemaker.csproj new file mode 100644 index 0000000..70f2f4a --- /dev/null +++ b/Runtime/Planets/Shoemaker/Shoemaker.csproj @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/Runtime/Planets/Shoemaker/Shoemaker.csproj.meta b/Runtime/Planets/Shoemaker/Shoemaker.csproj.meta new file mode 100644 index 0000000..4708c7d --- /dev/null +++ b/Runtime/Planets/Shoemaker/Shoemaker.csproj.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4578e594d8f1a3a4e8b70f297108421a +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Utility.meta b/Runtime/Planets/Shoemaker/Utility.meta new file mode 100644 index 0000000..b39d3f4 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Utility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 10aa8fe93f60d6c4daceb1a3e0617e5c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Utility/Extensions.cs b/Runtime/Planets/Shoemaker/Utility/Extensions.cs new file mode 100644 index 0000000..fe3e885 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Utility/Extensions.cs @@ -0,0 +1,10 @@ +namespace Shoemaker.Utility +{ + public static class Extensions + { + public static void Apply(this T? optional, ref T value) where T : struct + { + if (optional.HasValue) value = optional.Value; + } + } +} \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Utility/Extensions.cs.meta b/Runtime/Planets/Shoemaker/Utility/Extensions.cs.meta new file mode 100644 index 0000000..61237eb --- /dev/null +++ b/Runtime/Planets/Shoemaker/Utility/Extensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7bbd5a678e1094f46bd08e5bc9df1124 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs b/Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs new file mode 100644 index 0000000..9f4ca3c --- /dev/null +++ b/Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs @@ -0,0 +1,3 @@ +//global using static Shoemaker.Utility.Logging; +//global using UnityObject = UnityEngine.Object; +//global using static Shoemaker.Utility.Extensions; \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs.meta b/Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs.meta new file mode 100644 index 0000000..1e36a79 --- /dev/null +++ b/Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ace6a495938122248a1f925693787d2f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/swinfo.json b/Runtime/Planets/Shoemaker/swinfo.json new file mode 100644 index 0000000..0e6d9f3 --- /dev/null +++ b/Runtime/Planets/Shoemaker/swinfo.json @@ -0,0 +1,30 @@ +{ + "spec": "2.0", + "mod_id": "Shoemaker", + "author": "KSP2 Community", + "name": "Shoemaker", + "description": "A tool to enable planet modding for KSP2 via Patch Manager", + "source": "https://github.com/KSP2Community/Shoemaker", + "version": "0.1.0", + "version_check": "https://raw.githubusercontent.com/KSP2Community/Shoemaker/main/plugin_template/swinfo.json", + "ksp2_version": { + "min": "0.2.0", + "max": "*" + }, + "dependencies": [ + { + "id": "com.github.x606.spacewarp", + "version": { + "min": "1.8.0", + "max": "*" + } + }, + { + "id": "PatchManager", + "version": { + "min": "0.11.0", + "max": "*" + } + } + ] +} diff --git a/Runtime/Planets/Shoemaker/swinfo.json.meta b/Runtime/Planets/Shoemaker/swinfo.json.meta new file mode 100644 index 0000000..df5d958 --- /dev/null +++ b/Runtime/Planets/Shoemaker/swinfo.json.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 491793b9c667b7a4c9fbb09e2a4ba62b +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching.meta b/Runtime/SassyPatching.meta new file mode 100644 index 0000000..6ac0f83 --- /dev/null +++ b/Runtime/SassyPatching.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: ae951868a5cb40b9a6509df713ce8fb9 +timeCreated: 1739386780 \ No newline at end of file diff --git a/Runtime/SassyPatching/Attributes.meta b/Runtime/SassyPatching/Attributes.meta new file mode 100644 index 0000000..fa35c7a --- /dev/null +++ b/Runtime/SassyPatching/Attributes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 40628dd4f09c33d4e805da8b3ab27d19 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Attributes/PatcherRulesetAttribute.cs b/Runtime/SassyPatching/Attributes/PatcherRulesetAttribute.cs new file mode 100644 index 0000000..cfde099 --- /dev/null +++ b/Runtime/SassyPatching/Attributes/PatcherRulesetAttribute.cs @@ -0,0 +1,37 @@ +using System; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Interfaces; + +namespace PatchManager.SassyPatching.Attributes +{ + /// + /// Used to define that a class will be used in the patcher to "get" a ruleset + /// For example [PatcherRuleset("parts")] creates the ":parts" ruleset + /// + [AttributeUsage(AttributeTargets.Class)] + [BaseTypeRequired(typeof(IPatcherRuleSet))] + [MeansImplicitUse] + public class PatcherRulesetAttribute : Attribute + { + /// + /// The name of the ruleset + /// + public readonly string RulesetName; + + /// + /// Labels that should always be loaded, as this ruleset will match them + /// + public string[] PreloadLabels; + + /// + /// Used to define that a class will be used in the patcher to "get" a ruleset + /// + /// The name of the ruleset + /// Labels that should always be loaded, as this ruleset will match them + public PatcherRulesetAttribute(string rulesetName, params string[] preloadLabels) + { + RulesetName = rulesetName; + PreloadLabels = preloadLabels; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Attributes/PatcherRulesetAttribute.cs.meta b/Runtime/SassyPatching/Attributes/PatcherRulesetAttribute.cs.meta new file mode 100644 index 0000000..ee9bae4 --- /dev/null +++ b/Runtime/SassyPatching/Attributes/PatcherRulesetAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 16a2252a431ab6d409263ec5a0eebeb3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Attributes/SassyConstantAttribute.cs b/Runtime/SassyPatching/Attributes/SassyConstantAttribute.cs new file mode 100644 index 0000000..4db9062 --- /dev/null +++ b/Runtime/SassyPatching/Attributes/SassyConstantAttribute.cs @@ -0,0 +1,13 @@ +using System; +using JetBrains.Annotations; + +namespace PatchManager.SassyPatching.Attributes +{ + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + [MeansImplicitUse] + public class SassyConstantAttribute : Attribute + { + public string ConstantName; + public SassyConstantAttribute(string constantName) => ConstantName = constantName; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Attributes/SassyConstantAttribute.cs.meta b/Runtime/SassyPatching/Attributes/SassyConstantAttribute.cs.meta new file mode 100644 index 0000000..90e29b1 --- /dev/null +++ b/Runtime/SassyPatching/Attributes/SassyConstantAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5ca43e9943b4a5148ba5f3fd13648706 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Attributes/SassyLibraryAttribute.cs b/Runtime/SassyPatching/Attributes/SassyLibraryAttribute.cs new file mode 100644 index 0000000..2e2643a --- /dev/null +++ b/Runtime/SassyPatching/Attributes/SassyLibraryAttribute.cs @@ -0,0 +1,33 @@ +using System; +using JetBrains.Annotations; + +namespace PatchManager.SassyPatching.Attributes +{ + /// + /// Represents a builtin (C#) library for the sassy patcher execution engine + /// + [AttributeUsage(AttributeTargets.Class)] + [MeansImplicitUse] + public class SassyLibraryAttribute : Attribute + { + /// + /// The mod id of the library, this is the part before the ":" in an @use, doesn't have to correspond to the mod guid of the mod defining this library + /// + public string Mod; + /// + /// The actual name of the library, this is the part after the colon + /// + public string Library; + + /// + /// Define this as a builtin library + /// + /// The mod id of the library + /// The actual name of the library, this is the part after the colon + public SassyLibraryAttribute(string mod, string library) + { + Mod = mod; + Library = library; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Attributes/SassyLibraryAttribute.cs.meta b/Runtime/SassyPatching/Attributes/SassyLibraryAttribute.cs.meta new file mode 100644 index 0000000..245949a --- /dev/null +++ b/Runtime/SassyPatching/Attributes/SassyLibraryAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c824456f94454e4282cfbae8aa8f0bc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Attributes/SassyMethodAttribute.cs b/Runtime/SassyPatching/Attributes/SassyMethodAttribute.cs new file mode 100644 index 0000000..325f26b --- /dev/null +++ b/Runtime/SassyPatching/Attributes/SassyMethodAttribute.cs @@ -0,0 +1,28 @@ +using System; +using JetBrains.Annotations; + +namespace PatchManager.SassyPatching.Attributes +{ + /// + /// Defines this as a method for sassy patcher, it can define any argument type it wants, and reflection will be used to convert them at runtime + /// Method overloading is not allowed + /// + [AttributeUsage(AttributeTargets.Method)] + [MeansImplicitUse] + public class SassyMethodAttribute : Attribute + { + /// + /// The name of the method inside of the runtime this will be called + /// + public string MethodName; + + /// + /// Initializes a new SassyMethodAttribute + /// + /// The name of the method in runtime + public SassyMethodAttribute(string methodName) + { + MethodName = methodName; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Attributes/SassyMethodAttribute.cs.meta b/Runtime/SassyPatching/Attributes/SassyMethodAttribute.cs.meta new file mode 100644 index 0000000..f9386c0 --- /dev/null +++ b/Runtime/SassyPatching/Attributes/SassyMethodAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 35ecacbf2c8745c48973e603225cd2c4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Attributes/SassyNameAttribute.cs b/Runtime/SassyPatching/Attributes/SassyNameAttribute.cs new file mode 100644 index 0000000..e823873 --- /dev/null +++ b/Runtime/SassyPatching/Attributes/SassyNameAttribute.cs @@ -0,0 +1,14 @@ +using System; + +namespace PatchManager.SassyPatching.Attributes +{ + [AttributeUsage(AttributeTargets.Parameter,AllowMultiple = false)] + public class SassyNameAttribute : Attribute + { + public string ArgumentName; + public SassyNameAttribute(string argumentName) + { + ArgumentName = argumentName; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Attributes/SassyNameAttribute.cs.meta b/Runtime/SassyPatching/Attributes/SassyNameAttribute.cs.meta new file mode 100644 index 0000000..09a4a9d --- /dev/null +++ b/Runtime/SassyPatching/Attributes/SassyNameAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 443be4c6b2fd5d34a9158a367e7cc7aa +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Attributes/VarArgsAttribute.cs b/Runtime/SassyPatching/Attributes/VarArgsAttribute.cs new file mode 100644 index 0000000..15814b6 --- /dev/null +++ b/Runtime/SassyPatching/Attributes/VarArgsAttribute.cs @@ -0,0 +1,13 @@ +using System; + +namespace PatchManager.SassyPatching.Attributes +{ + /// + /// Used on a parameter for a builtin method to change it from matching List<Value> to all the remaining arguments + /// + [AttributeUsage(AttributeTargets.Parameter)] + public class VarArgsAttribute : Attribute + { + + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Attributes/VarArgsAttribute.cs.meta b/Runtime/SassyPatching/Attributes/VarArgsAttribute.cs.meta new file mode 100644 index 0000000..a14bef9 --- /dev/null +++ b/Runtime/SassyPatching/Attributes/VarArgsAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9cc772bdecbd62b49861ba6da1757991 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/BaseSelectable.cs b/Runtime/SassyPatching/BaseSelectable.cs new file mode 100644 index 0000000..aed0a55 --- /dev/null +++ b/Runtime/SassyPatching/BaseSelectable.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Utility; + +namespace PatchManager.SassyPatching +{ + /// + /// A base class for selectables that implements most of the selection functions + /// + [PublicAPI] + public abstract class BaseSelectable : ISelectable + { + /// + /// The children of this selectable + /// + public abstract List Children { get; } + + /// + public List SelectEverything() => Children; + + /// + /// The name of this selectable element + /// + public abstract string Name { get; } + + /// + public bool MatchesName(string name) => Name.MatchesPattern(name); + + /// + /// The classes that this selectable has, usually corresponds to the field names of the children (except for parts, in which its that + module type) + /// + public abstract List Classes { get; } + + /// + public bool MatchesClass(string @class) => Classes.Contains(@class); + + /// + /// Test if this selectable has a class, and if so, output the value of that class + /// + /// The class + /// The value of the class + /// True if it has the class, false otherwise + public abstract bool MatchesClass(string @class, out DataValue classValue); + + /// + /// The type of this selectable element (usually corresponds to the field name it is defined as, or the module type) + /// + public abstract string ElementType { get; } + + /// + public bool MatchesElement(string element) => ElementType == element; + + /// + public abstract bool IsSameAs(ISelectable other); + + /// + public abstract IModifiable OpenModification(); + + + + /// + public abstract ISelectable AddElement(string elementType); + + + /// + public abstract string Serialize(); + + /// + + public abstract DataValue GetValue(); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/BaseSelectable.cs.meta b/Runtime/SassyPatching/BaseSelectable.cs.meta new file mode 100644 index 0000000..4545e0a --- /dev/null +++ b/Runtime/SassyPatching/BaseSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 32c7f528497846e45a3372fe82c671cc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Builtins.meta b/Runtime/SassyPatching/Builtins.meta new file mode 100644 index 0000000..4180691 --- /dev/null +++ b/Runtime/SassyPatching/Builtins.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cfbb31ab205e9b644ac8806a775fbf1b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Builtins/ConfigBuiltins.cs b/Runtime/SassyPatching/Builtins/ConfigBuiltins.cs new file mode 100644 index 0000000..b93b068 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/ConfigBuiltins.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Execution; + +namespace PatchManager.SassyPatching.Builtins +{ + [SassyLibrary("builtin", "config")] + public class ConfigBuiltins + { + [SassyMethod("get-config")] + public static DataValue GetConfig(Universe universe, string label, string name) => + universe.Configs.TryGetValue(label, out var labelDict) + ? labelDict.TryGetValue(name, out var result) ? result : new DataValue(DataValue.DataType.None) + : new DataValue(DataValue.DataType.None); + + [SassyMethod("get-configs")] + public static DataValue GetConfigs(Universe universe, string label) => + universe.Configs.TryGetValue(label, out var labelDict) ? labelDict : new Dictionary(); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Builtins/ConfigBuiltins.cs.meta b/Runtime/SassyPatching/Builtins/ConfigBuiltins.cs.meta new file mode 100644 index 0000000..1dde509 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/ConfigBuiltins.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 998082e3f41eafa4f9f56ddd47b26ef0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Builtins/DebugBuiltins.cs b/Runtime/SassyPatching/Builtins/DebugBuiltins.cs new file mode 100644 index 0000000..e332d28 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/DebugBuiltins.cs @@ -0,0 +1,35 @@ +using JetBrains.Annotations; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Execution; + +namespace PatchManager.SassyPatching.Builtins +{ + /// + /// Contains a lot of builtin debug libraries for the sassy patch engine to use + /// + [SassyLibrary("builtin","debug"),PublicAPI] + public class DebugBuiltins + { + /// + /// Logs a value into the console for debugging + /// + /// The universe in which this function is being called + /// The value to log + [SassyMethod("debug-log")] + public static void Log(Universe universe, DataValue value) + { + universe.MessageLogger(value.Type == DataValue.DataType.String ? value.String : value.ToString()); + } + + /// + /// Serializes a value + /// + /// The value to serialize + /// The serialized form of the value + [SassyMethod("serialize")] + public static string Serialize(DataValue value) + { + return value.ToString(); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Builtins/DebugBuiltins.cs.meta b/Runtime/SassyPatching/Builtins/DebugBuiltins.cs.meta new file mode 100644 index 0000000..801d76f --- /dev/null +++ b/Runtime/SassyPatching/Builtins/DebugBuiltins.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1b0959ac0a0ba3d47bad4e22721e279d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Builtins/DictionaryBuiltins.cs b/Runtime/SassyPatching/Builtins/DictionaryBuiltins.cs new file mode 100644 index 0000000..0b6eee2 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/DictionaryBuiltins.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Attributes; +using UniLinq; + +namespace PatchManager.SassyPatching.Builtins +{ + /// + /// Object/dictionary builtins + /// + [SassyLibrary("builtin","dictionary")] + [PublicAPI] + public class DictionaryBuiltins + { + [SassyMethod("dictionary.set")] + public static Dictionary Set(Dictionary dict, string key, DataValue value) + { + var result = new Dictionary(dict); + if (value.IsDeletion) + { + result.Remove(key); + } + else + { + result[key] = value; + } + return result; + } + + [SassyMethod("dictionary.merge")] + public static Dictionary Merge( + [SassyName("original-dict")] Dictionary original, + [SassyName("new-dict")] Dictionary toMerge + ) + { + var newDictionary = new Dictionary(original); + foreach (var (key, value) in toMerge) + { + newDictionary[key] = value; + } + return newDictionary; + } + + [SassyMethod("dictionary.keys")] + public static List Keys(Dictionary dict) => dict.Keys.ToList(); + + [SassyMethod("dictionary.values")] + public static List Values(Dictionary dict) => dict.Values.ToList(); + + + [SassyMethod("dictionary.remove")] + public static Dictionary Remove(Dictionary dict, string key) => + dict.Where(kv => kv.Key != key).ToDictionary(kv => kv.Key,kv=>kv.Value); + + [SassyMethod("dictionary.count")] + public static int Count(Dictionary dict) => dict.Count; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Builtins/DictionaryBuiltins.cs.meta b/Runtime/SassyPatching/Builtins/DictionaryBuiltins.cs.meta new file mode 100644 index 0000000..92a4c1d --- /dev/null +++ b/Runtime/SassyPatching/Builtins/DictionaryBuiltins.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 55874c2d80cab324f81f13706b535ff2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Builtins/FunctionalBuiltins.cs b/Runtime/SassyPatching/Builtins/FunctionalBuiltins.cs new file mode 100644 index 0000000..f01ac93 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/FunctionalBuiltins.cs @@ -0,0 +1,80 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Execution; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Builtins +{ + [SassyLibrary("builtin","functional"),PublicAPI] + public class FunctionalBuiltins + { + + + /// + /// Gets a function from the global environment + /// + /// The global environment that is automatically filled in + /// The name of the function to get + /// A closure representing that function + [SassyMethod("get-function")] + public static PatchFunction GetFunction(GlobalEnvironment globalEnvironment, string name) + { + return globalEnvironment.AllFunctions[name]; + } + + /// + /// Invoke a closure w/ the given arguments + /// + /// The environment to run the closure in + /// + /// + /// + [SassyMethod("closure.invoke")] + public static DataValue Invoke(Environment env, PatchFunction closure, List arguments) + { + return closure.Execute(env, arguments); + } + + + /// + /// Binds arguments to the left side of a closure + /// + /// The closure to bind the arguments to + /// The arguments to be bound + /// A method that is the closure w/ the arguments having been bound + [SassyMethod("closure.bind")] + public static PatchFunction Bind(PatchFunction closure, List arguments) + { + if (closure is BoundPatchFunction boundPatchFunction) + { + var leftBindings = new List(boundPatchFunction.LeftBindings); + leftBindings.AddRange(arguments); + return new BoundPatchFunction(boundPatchFunction.InternalFunction, leftBindings, boundPatchFunction.RightBindings); + } + return new BoundPatchFunction(closure, arguments, new()); + } + + /// + /// Binds arguments to the right side of a closure + /// + /// The closure to bind the arguments to + /// The arguments to be bound + /// A method that is the closure w/ the arguments having been bound + [SassyMethod("closure.right-bind")] + public static PatchFunction RightBind(PatchFunction closure, List arguments) + { + if (closure is BoundPatchFunction boundPatchFunction) + { + // Make sure they get bound before the already right bound functions + // $x:right-bind(1):right-bind(2) should be equivalent to $x:right-bind(2,1) + var rightBindings = new List(arguments); + rightBindings.AddRange(boundPatchFunction.RightBindings); + return new BoundPatchFunction(boundPatchFunction.InternalFunction, boundPatchFunction.LeftBindings,rightBindings); + } + + return new BoundPatchFunction(closure, new(), arguments); + } + + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Builtins/FunctionalBuiltins.cs.meta b/Runtime/SassyPatching/Builtins/FunctionalBuiltins.cs.meta new file mode 100644 index 0000000..0f6c648 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/FunctionalBuiltins.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ec603335b2070db44a9efd50b7a9b735 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Builtins/ListBuiltins.cs b/Runtime/SassyPatching/Builtins/ListBuiltins.cs new file mode 100644 index 0000000..6c11d7f --- /dev/null +++ b/Runtime/SassyPatching/Builtins/ListBuiltins.cs @@ -0,0 +1,236 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Execution; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Builtins +{ + /// + /// This is the list library used by sassy patching, every method that is list specific in it is prepended w/ list. to prevent overloading + /// + [SassyLibrary("builtin", "list")] + [PublicAPI] + public class ListBuiltins + { + /// + /// Copies a list and appends a value onto the copy and returns the copy + /// + /// The list to copy + /// The value to append + /// The new list w/ the value appended to it + [SassyMethod("list.append")] + public static List Append(List list, DataValue value) => new(list) { value }; + + /// + /// Copies a list and appends a list of values onto the copy and returns the copy + /// Same as the `+` operator between lists + /// + /// The list to copy + /// The list of values to append + /// The new list w/ the values appended to it + [SassyMethod("list.append-all")] + public static List AppendAll(List list, List values) + { + var result = new List(list); + result.AddRange(values); + return result; + } + + /// + /// Creates a new list out + /// + /// + /// + [SassyMethod("list.create")] + public static List Create([VarArgs] List varArgs) + { + return varArgs; + } + + private static int DefaultComparison(DataValue a, DataValue b) + { + if (a.IsInteger && b.IsInteger) + { + return a.Integer < b.Integer ? -1 : a.Integer == b.Integer ? 0 : 1; + } + + if (a.IsReal && b.IsInteger) + { + // ReSharper disable once CompareOfFloatsByEqualityOperator + return a.Real < b.Integer ? -1 : a.Real == b.Integer ? 0 : 1; + } + + if (a.IsInteger && b.IsReal) + { + // ReSharper disable once CompareOfFloatsByEqualityOperator + return a.Integer < b.Real ? -1 : a.Integer == b.Real ? 0 : 1; + } + + if (a.IsReal && b.IsReal) + { + // ReSharper disable once CompareOfFloatsByEqualityOperator + return a.Real < b.Real ? -1 : a.Real == b.Real ? 0 : 1; + } + + if (a.IsString && b.IsString) + { + return string.Compare(a.String, b.String, StringComparison.Ordinal); + } + + throw new Exception( + $"Cannot compare a value of type {a.Type.ToString().ToLowerInvariant()} and {b.Type.ToString().ToLowerInvariant()}"); + } + + private static int InvokeComparison(Environment env, PatchFunction comparator, DataValue a, DataValue b) + { + var result = comparator.Execute(env, new List + { + new PatchArgument + { + ArgumentDataValue = a + }, + new PatchArgument + { + ArgumentDataValue = b + }, + }); + if (result.IsInteger) + { + // A simple are these less + return (int)result.Integer; + } + + if (result.IsReal) + { + return (int)result.Real; + } + + throw new TypeConversionException(result.Type.ToString().ToLowerInvariant(), "integer"); + } + + /// + /// Sorts a list, using a comparison function if one is provided otherwise uses a default comparison algorithm + /// + /// + /// + /// The function to sort with, default null (due to closures not existing in the program yet), follows the C# comparison function + /// + [SassyMethod("list.sort")] + public static List Sort(Environment env, List list, PatchFunction comparator = null) + { + var copy = new List(list); + Comparison comparison = + comparator != null ? (x, y) => InvokeComparison(env, comparator, x, y) : DefaultComparison; + copy.Sort(comparison); + return copy; + } + + + /// + /// Copy a list, apply a function over the copy and return that copy + /// + /// The environment this is being ran in + /// + /// The function to apply to the list + /// The copy w/ the function applied over it + [SassyMethod("list.map")] + public static List Map( + Environment env, + List list, + PatchFunction closure + ) => + list.Select(value => closure.Execute(env, + new List + { + new() + { + ArgumentDataValue = value + } + })) + .ToList(); + + /// + /// Copy a list, apply a function over the copy to filter the lists + /// + /// The environment this is being ran in + /// + /// The function to apply to the list + /// The copy w/ the function applied over it + [SassyMethod("list.filter")] + public static List Filter( + Environment env, + List list, + PatchFunction closure + ) => + list.Where(value => closure.Execute(env, + new List + { + new() + { + ArgumentDataValue = value + } + }).Truthy) + .ToList(); + + /// + /// Aggregate a list into one value + /// + /// The environment of the list + /// + /// The starting value of the aggregation + /// The function to apply to take the aggregate + /// The aggregate value + [SassyMethod("list.reduce")] + public static DataValue Reduce( + Environment env, + List list, + [SassyName("initial-value")] DataValue initialValue, + PatchFunction closure + ) => + list.Aggregate(initialValue, + ( + current, + value + ) => closure.Execute(env, + new List + { + new() + { + ArgumentDataValue = current + }, + new() + { + ArgumentDataValue = value + } + })); + + /// + /// Gets the length of a list + /// + /// The list + /// The length of the list + [SassyMethod("list.length")] + public static int Length(List list) => list.Count; + + [SassyMethod("list.join")] + public static string ToString(List list, string separator = "") => + string.Join("", list.Select(x => x.IsString ? x.String : x.ToString())); + + [SassyMethod("list.remove")] + public static List Remove(List list, [SassyName("to-remove")] DataValue toRemove) => + list.Where(x => x != toRemove).ToList(); + + [SassyMethod("list.remove-all")] + public static List RemoveAll(List list, [SassyName("to-remove")] List toRemove) => + list.Where(x => toRemove.All(y => y != x)).ToList(); + + [SassyMethod("list.slice")] + public static List Slice(List list, int start, int end) => + list.Skip(start).Take(end-start).ToList(); + + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Builtins/ListBuiltins.cs.meta b/Runtime/SassyPatching/Builtins/ListBuiltins.cs.meta new file mode 100644 index 0000000..f4676e7 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/ListBuiltins.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 09a6fbfb2315933468d272f46b46d7ba +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Builtins/MathBuiltins.cs b/Runtime/SassyPatching/Builtins/MathBuiltins.cs new file mode 100644 index 0000000..a6ad934 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/MathBuiltins.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Attributes; +using UniLinq; + +namespace PatchManager.SassyPatching.Builtins +{ + /// + /// A builtin math library to make dealing with stuff easier + /// + [SassyLibrary("builtin", "math"), PublicAPI] + public class MathBuiltins + { + #region Basic Math + + [SassyMethod("square-root")] + public static double SquareRoot(double value) => Math.Sqrt(value); + + [SassyMethod("cube-root")] + public static double CubeRoot(double value) => Math.Pow(value, 0.333333333333333333333333333333333333333333333333d); + + [SassyMethod("pow")] + public static double Pow(double x, double y) => Math.Pow(x, y); + + [SassyMethod("ln")] + public static double Ln(double a) => Math.Log(a); + + [SassyMethod("log")] + public static double Log(double a, double @base) => Math.Log(a, @base); + + [SassyMethod("log10")] + public static double Log10(double a) => Math.Log10(a); + + [SassyMethod("ceiling")] + public static double Ceiling(double a) => Math.Ceiling(a); + + [SassyMethod("floor")] + public static double Floor(double a) => Math.Floor(a); + + [SassyMethod("abs")] + public static double Abs(double a) => Math.Abs(a); + + [SassyMethod("max")] + public static double Max([VarArgs] List values) => values.Select(x => x.To()).Max(); + + [SassyMethod("min")] + public static double Min([VarArgs] List values) => values.Select(x => x.To()).Min(); + + [SassyMethod("list.max")] + public static double Max(List list) => list.Max(); + + [SassyMethod("list.min")] + public static double Min(List list) => list.Min(); + + [SassyMethod("round")] + public static double Round(double x) => Math.Round(x, MidpointRounding.AwayFromZero); + + [SassyMethod("sign")] + public static double Sign(double x) => Math.Sign(x); + + [SassyConstant("E")] public static double E => Math.E; + + #endregion + + #region Trigonometry + + [SassyMethod("sin")] + public static double Sin(double a) => Math.Sin(a); + + [SassyMethod("cos")] + public static double Cos(double a) => Math.Cos(a); + + [SassyMethod("tan")] + public static double Tan(double a) => Math.Tan(a); + + [SassyMethod("sinh")] + public static double Sinh(double a) => Math.Sinh(a); + + [SassyMethod("cosh")] + public static double Cosh(double a) => Math.Cosh(a); + + [SassyMethod("tanh")] + public static double Tanh(double a) => Math.Tanh(a); + + [SassyMethod("asin")] + public static double Asin(double a) => Math.Asin(a); + + [SassyMethod("acos")] + public static double Acos(double a) => Math.Acos(a); + + [SassyMethod("atan")] + public static double Atan(double a) => Math.Atan(a); + + [SassyMethod("atan2")] + public static double Atan2(double y, double x) => Math.Atan2(y, x); + + [SassyConstant("PI")] public static double Pi => Math.PI; + [SassyConstant("TAU")] public static double Tau => 2 * Pi; + + #endregion + + #region Other Math + + [SassyMethod("interpolate")] + public static double Lerp(double a, double b, double t) => (1 - t) * a + t * b; + + [SassyMethod("list.normalize")] + public static List Normalize(List vector) + { + var magnitude = Math.Sqrt(vector.Select(x => x * x).Sum()); + return vector.Select(x => x / magnitude).ToList(); + } + + [SassyMethod("normalize")] + public static List Normalize([VarArgs] List args) + { + var list = (from x in args select x.To()).ToList(); + return Normalize(list); + } + + + #endregion + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Builtins/MathBuiltins.cs.meta b/Runtime/SassyPatching/Builtins/MathBuiltins.cs.meta new file mode 100644 index 0000000..e73447c --- /dev/null +++ b/Runtime/SassyPatching/Builtins/MathBuiltins.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e002ed5e4eaf7df4cbb65eac9d65c1cd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Builtins/MetaBuiltins.cs b/Runtime/SassyPatching/Builtins/MetaBuiltins.cs new file mode 100644 index 0000000..0502587 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/MetaBuiltins.cs @@ -0,0 +1,20 @@ +using JetBrains.Annotations; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Execution; +using UniLinq; + +namespace PatchManager.SassyPatching.Builtins +{ + [SassyLibrary("builtin","meta")] + [PublicAPI] + public class MetaBuiltins + { + [SassyMethod("exists-mod")] + public static bool ExistsMod(GlobalEnvironment globalEnvironment, [SassyName("mod-name")] string modName) => globalEnvironment.Universe.AllMods.Contains(modName); + + [SassyMethod("exists-function")] + public static bool ExistsFunction(GlobalEnvironment environment, [SassyName("function-name")] string functionName) => + environment.AllFunctions.Keys.Contains(functionName); + + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Builtins/MetaBuiltins.cs.meta b/Runtime/SassyPatching/Builtins/MetaBuiltins.cs.meta new file mode 100644 index 0000000..015bc7e --- /dev/null +++ b/Runtime/SassyPatching/Builtins/MetaBuiltins.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d57e614d09db99043880a233f077b54c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Builtins/ReflectionBuiltins.cs b/Runtime/SassyPatching/Builtins/ReflectionBuiltins.cs new file mode 100644 index 0000000..20c8374 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/ReflectionBuiltins.cs @@ -0,0 +1,24 @@ +using JetBrains.Annotations; +using PatchManager.SassyPatching.Attributes; + +namespace PatchManager.SassyPatching.Builtins +{ + /// + /// This is the reflection library used by Sassy patching, its very simple as not much reflection is needed by the language + /// + [SassyLibrary("builtin","reflection")] + [PublicAPI] + public class ReflectionBuiltins + { + /// + /// Gets the type of a value + /// + /// The value to get the type of + /// The values type as a lowercase string + [SassyMethod("typeof")] + public static string GetValueType(DataValue value) + { + return value.Type.ToString().ToLowerInvariant(); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Builtins/ReflectionBuiltins.cs.meta b/Runtime/SassyPatching/Builtins/ReflectionBuiltins.cs.meta new file mode 100644 index 0000000..a3a9295 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/ReflectionBuiltins.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 791e74d8cf5e583439a9c8a0ac2e7eea +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Builtins/StringBuiltins.cs b/Runtime/SassyPatching/Builtins/StringBuiltins.cs new file mode 100644 index 0000000..89f38b7 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/StringBuiltins.cs @@ -0,0 +1,44 @@ +using JetBrains.Annotations; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Exceptions; +using UniLinq; + +namespace PatchManager.SassyPatching.Builtins +{ + /// + /// This contains all the builtin methods applying over strings + /// + [SassyLibrary("builtin","string"),PublicAPI] + public class StringBuiltins + { + [SassyMethod("string.length")] + public static int Length([SassyName("string")] string str) => str.Length; + + [SassyMethod("string.reverse")] + public static string Reverse([SassyName("string")] string str) => string.Join("",str.Reverse()); + + [SassyMethod("string.starts-with")] + public static bool StartsWith([SassyName("string")] string str, [SassyName("other-string")] string otherString) => + str.StartsWith(otherString); + + + [SassyMethod("string.ends-with")] + public static bool EndsWith([SassyName("string")] string str, [SassyName("other-string")] string otherString) => + str.EndsWith(otherString); + + [SassyMethod("string.contains")] + public static bool Contains([SassyName("string")] string str, [SassyName("other-string")] string otherString) => + str.Contains(otherString); + + [SassyMethod("string.to-codepoint")] + public static char ToCodePoint([SassyName("string")] string str) + { + if (str.Length != 1) + throw new InvocationException("The length of the argument string must be one"); + return str[0]; + } + + [SassyMethod("codepoint-to-string")] + public static string CodePointToString([SassyName("codepoint")] char codePoint) => $"{codePoint}"; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Builtins/StringBuiltins.cs.meta b/Runtime/SassyPatching/Builtins/StringBuiltins.cs.meta new file mode 100644 index 0000000..ae7ffcc --- /dev/null +++ b/Runtime/SassyPatching/Builtins/StringBuiltins.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: bc66970a60f1c854da70379ac955c5a6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Builtins/TypeConversion.cs b/Runtime/SassyPatching/Builtins/TypeConversion.cs new file mode 100644 index 0000000..b30dbb1 --- /dev/null +++ b/Runtime/SassyPatching/Builtins/TypeConversion.cs @@ -0,0 +1,90 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Attributes; +using UniLinq; + +namespace PatchManager.SassyPatching.Builtins +{ + /// + /// This contains all the builtin methods for converting between types + /// + [SassyLibrary("builtin","type-conversion"),PublicAPI] + public class TypeConversion + { + /// + /// Used in a patch to convert a value to a boolean + /// + /// The value + /// A boolean form of the value + [SassyMethod("to-bool")] + public static bool ToBoolean(DataValue value) => value.Truthy; + + + /// + /// Used in a patch to convert a value to a real + /// + /// The value + /// The value interpreted as a real + [SassyMethod("to-real")] + public static double ToReal(DataValue value) + { + if (value.IsInteger) return value.Integer; + if (value.IsReal) return value.Real; + if (value.IsString) return double.Parse(value.String); + throw new InvalidCastException($"Cannot convert value of type {value.Type.ToString().ToLowerInvariant()} to real"); + } + + /// + /// Used in a patch to convert a value to a real + /// + /// The value + /// The value interpreted as a real + [SassyMethod("to-integer")] + public static long ToInteger(DataValue value) + { + if (value.IsInteger) return value.Integer; + if (value.IsReal) return (long)value.Real; + if (value.IsString) return long.Parse(value.String); + throw new InvalidCastException($"Cannot convert value of type {value.Type.ToString().ToLowerInvariant()} to integer"); + } + + /// + /// Used in a patch to convert a value to a string + /// + /// The value + /// A string form of the value + [SassyMethod("to-string")] + public static string ToString(DataValue value) + { + return value.IsString ? value.String : value.ToString(); + } + + [SassyMethod("dictionary.to-list")] + public static List> ToList(Dictionary dict) => dict.Select(kv => + new List() + { + DataValue.From(kv.Key), + kv.Value + }).ToList(); + + [SassyMethod("list.to-dictionary")] + public static Dictionary ToDictionary(List> list) + { + var newDict = new Dictionary(); + foreach (var value in list) + { + if (value.Count != 2) + throw new InvalidCastException("All values in $list must be 2-pairs of key, value"); + if (!value[0].IsString) + throw new InvalidCastException("Dictionary keys must be strings"); + newDict[value[0].String] = value[1]; + } + return newDict; + } + + [SassyMethod("string.to-list")] + public static List ToList([SassyName("string")] string str) => str.Select(x => $"{x}").ToList(); + + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Builtins/TypeConversion.cs.meta b/Runtime/SassyPatching/Builtins/TypeConversion.cs.meta new file mode 100644 index 0000000..dfaa78e --- /dev/null +++ b/Runtime/SassyPatching/Builtins/TypeConversion.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 397f47d8764dc1c43a7d32c9ffd9c233 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Coordinate.cs b/Runtime/SassyPatching/Coordinate.cs new file mode 100644 index 0000000..0bdc2ce --- /dev/null +++ b/Runtime/SassyPatching/Coordinate.cs @@ -0,0 +1,31 @@ +namespace PatchManager.SassyPatching +{ + /// + /// Defines a location in a file + /// + /// The file the location is in + /// The line of the location + /// The column of the location + public struct Coordinate + { + public Coordinate(string filename, int line, int column) + { + Filename = filename; + Line = line; + Column = column; + } + + public string Filename { get; } + public int Line { get; } + public int Column { get; } + + /// + /// Get the string representation of the location + /// + /// A string representation in file:line:column format + public override string ToString() + { + return $"{Filename}:{Line}:{Column}"; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Coordinate.cs.meta b/Runtime/SassyPatching/Coordinate.cs.meta new file mode 100644 index 0000000..bc0b8fe --- /dev/null +++ b/Runtime/SassyPatching/Coordinate.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 41acd7004a106844c892add33ab914e9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/DataValue.cs b/Runtime/SassyPatching/DataValue.cs new file mode 100644 index 0000000..2be79dd --- /dev/null +++ b/Runtime/SassyPatching/DataValue.cs @@ -0,0 +1,1317 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Utility; +using UniLinq; + +namespace PatchManager.SassyPatching +{ + /// + /// The basic value type that the sassy patching engine uses + /// It can be one of 8 different types of values, 6 of which correspond fully to JSON types w/ one extra type/value meant to "delete" whatever it is assigned to, and then closures + /// + public class DataValue + { + /// + /// The types of values that a Value can be + /// + public enum DataType + { + /// + /// The type of null, corresponds to JSON null values + /// + None, + /// + /// The type of true/false, corresponds to JSON true/false values + /// + Boolean, + /// + /// The type of real numbers, stored as a double, corresponds to JSON floats + /// + Real, + /// + /// The type of integers, stored as a long, corresponds to JSON integers + /// + Integer, + /// + /// The type of strings, corresponds to JSON strings + /// + String, + /// + /// The type of lists, corresponds to JSON lists + /// + List, + /// + /// The type of dictionaries, corresponds to JSON objects + /// + Dictionary, + /// + /// The type of a value that when assigned to a variable/field deletes that variable/field + /// + Deletion, + + /// + /// The type of a closure, a function in a value + /// + Closure, + } + + /// + /// The type of this Value + /// + public readonly DataType Type; + + private readonly object _object; + + /// + /// Creates a new value w/ a specified type and stored value + /// + /// The type of this value + /// The value that is stored in this value, can be null for values of type and + public DataValue(DataType type, object o = null) + { + Type = type; + _object = o; + } + + private void CheckType(DataType toCheck) + { + if (Type != toCheck) + { + throw new IncorrectTypeException($"Attempting to read Value of type {Type} as a value of type {toCheck}"); + } + } + + /// + /// Is the type of this variable ? + /// + public bool IsNone => Type == DataType.None; + + /// + /// Is the type of this variable ? + /// + public bool IsBoolean => Type == DataType.Boolean; + + /// + /// Asserts this value is of type , + /// then returns the contained within + /// + /// Thrown if this value is not a value of type + public bool Boolean + { + get + { + CheckType(DataType.Boolean); + return (bool)_object; + } + } + + /// + /// Is the type of this variable ? + /// + public bool IsReal => Type == DataType.Real; + + /// + /// Asserts this value is of type , + /// then returns the contained within + /// + /// Thrown if this value is not a value of type + public double Real + { + get + { + CheckType(DataType.Real); + return (double)_object; + } + } + + /// + /// Is the type of this variable ? + /// + public bool IsInteger => Type == DataType.Integer; + + /// + /// Asserts this value is of type , + /// then returns the contained within + /// + /// Thrown if this value is not a value of type + public long Integer + { + get + { + CheckType(DataType.Integer); + return (long)_object; + } + } + + + /// + /// Is the type of this variable ? + /// + public bool IsString => Type == DataType.String; + + /// + /// Asserts this value is of type , + /// then returns the contained within + /// + /// Thrown if this value is not a value of type + public string String + { + get + { + CheckType(DataType.String); + return (string)_object; + } + } + + /// + /// Is the type of this variable ? + /// + public bool IsList => Type == DataType.List; + + /// + /// Asserts this value is of type , + /// then returns the contained within of which generic type argument is + /// + /// Thrown if this value is not a value of type + public List List + { + get + { + CheckType(DataType.List); + return (List)_object; + } + } + + /// + /// Is the type of this variable ? + /// + public bool IsDictionary => Type == DataType.Dictionary; + + /// + /// Asserts this value is of type , + /// then returns the contained within of which the key type is and the value type is + /// + /// Thrown if this value is not a value of type + public Dictionary Dictionary + { + get + { + CheckType(DataType.Dictionary); + return (Dictionary)_object; + } + } + + /// + /// Is the type of this variable ? + /// + public bool IsDeletion => Type == DataType.Deletion; + + /// + /// Is the type of this variable ? + /// + public bool IsClosure => Type == DataType.Closure; + + /// + /// Asserts this value is of type , + /// then returns the contained within + /// + /// Thrown if this value is not a value of type + public PatchFunction Closure + { + get + { + CheckType(DataType.Closure); + return (PatchFunction)_object; + } + } + + + /// + /// Does this value get interpreted as true in places where a is expected? + /// That is, is the value a and the value stored within true, or is the value anything but and ? + /// + public bool Truthy { + get + { + if (IsBoolean) return Boolean; + return !(IsNone || IsDeletion); + } + } + + /// + /// Creates a from a + /// + /// The value to be stored within the value + /// A with a type of and a stored value of + public static implicit operator DataValue(bool b) + { + return new DataValue(DataType.Boolean, b); + } + + /// + /// Creates a from a + /// + /// The value to be stored within the value + /// A with a type of and a stored value of + public static implicit operator DataValue(double d) + { + return new DataValue(DataType.Real, d); + } + + /// + /// Creates a from a + /// + /// The value to be stored within the value + /// A with a type of and a stored value of + public static implicit operator DataValue(long l) + { + return new DataValue(DataType.Integer, l); + } + + + /// + /// Creates a from a + /// + /// The value to be stored within the value + /// A with a type of and a stored value of + public static implicit operator DataValue(string s) + { + return new DataValue(DataType.String, s); + } + + /// + /// Creates a from a with the generic type argument being + /// + /// The value to be stored within the value + /// A with a type of and a stored value of + public static implicit operator DataValue(List l) + { + return new DataValue(DataType.List, l); + } + + /// + /// Creates a from a with the key type being and value type being + /// + /// The value to be stored within the value + /// A with a type of and a stored value of + public static implicit operator DataValue(Dictionary d) + { + return new DataValue(DataType.Dictionary, d); + } + + /// + /// Creates a from a + /// + /// The value to be stored within the value + /// A with a type of and a stored value of + public static implicit operator DataValue(PatchFunction c) + { + return new DataValue(DataType.Closure, c); + } + + /// + /// Converts a value to a string representation that can be interpreted by the engine as the exact value + /// + /// The string representation of the value + public override string ToString() + { + if (IsNone) + { + return "null"; + } + + if (IsBoolean) + { + return Boolean.ToString(); + } + + if (IsReal) + { + return Real.ToString(CultureInfo.InvariantCulture); + } + + if (IsString) + { + // return "'" + Regex.Escape(String) + "'"; + return String.Escape(); + } + + if (IsList) + { + return "[" + string.Join(",",List.Select(x => x.ToString())) + "]"; + } + + if (IsDictionary) + { + return "{" + string.Join(",",Dictionary.Select(x => x.Key.Escape() + $":{x.Value}")) + "}"; + } + + if (IsDeletion) + { + return "@delete"; + } + + if (IsClosure) + { + return ""; + } + + return ""; + } + + public T To() => (T)To(typeof(T)); + + public object To(Type t) + { + if (t == typeof(DataValue)) + { + return this; + } + + if (t == typeof(string)) + { + return String; + } + + if (t == typeof(Dictionary)) + { + return Dictionary; + } + + if (t == typeof(List)) + { + return List; + } + + if (t == typeof(DataValue[])) + { + return List.ToArray(); + } + + if (t == typeof(byte)) + { + return (byte)Integer; + } + + if (t == typeof(sbyte)) + { + return (sbyte)Integer; + } + + if (t == typeof(short)) + { + return (short)Integer; + } + + if (t == typeof(ushort)) + { + return (ushort)Integer; + } + + if (t == typeof(int)) + { + return (int)Integer; + } + + if (t == typeof(uint)) + { + return (uint)Integer; + } + + if (t == typeof(long)) + { + // ReSharper disable once RedundantCast + return (long)Integer; + } + + if (t == typeof(ulong)) + { + return (ulong)Integer; + } + + if (t == typeof(float)) + { + return (float)Real; + } + + if (t == typeof(double)) + { + return Real; + } + + if (t == typeof(bool)) + { + return Boolean; + } + + if (t == typeof(PatchFunction)) + { + return Closure; + } + + if (Type == DataType.None) + { + return null; + } + + if (ConvertValueToSingleRankArray(t, out var singleRankArray)) return singleRankArray; + + if (ConvertValueToMultiRankArray(t, out var multiRankArray)) return multiRankArray; + + if (ConvertValueToList(t, out var list)) return list; + + if (ConvertValueToDictionary(t, out var convertParameterValue)) return convertParameterValue; + + var obj = Activator.CreateInstance(t); + var dictionary = Dictionary; + foreach (var field in t.GetFields()) + { + field.SetValue(obj, dictionary[field.Name].To(field.FieldType)); + } + + return obj; + } + + private bool ConvertValueToDictionary(Type type, out object dictionary) + { + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) + { + var keyType = type.GetGenericArguments()[0]; + var valueType = type.GetGenericArguments()[1]; + if (keyType != typeof(string)) + { + throw new TypeConversionException("Value", type.Name); + } + + var id = (IDictionary)Activator.CreateInstance(type); + var dict = Dictionary; + foreach (var kv in dict) + { + id[kv.Key] = kv.Value.To(valueType); + } + + { + dictionary = id; + return true; + } + } + + dictionary = null; + return false; + } + + private bool ConvertValueToList(Type type, out object list) + { + if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) + { + var valueType = type.GetGenericArguments()[0]; + var il = (IList)Activator.CreateInstance(type); + var tab = List; + foreach (var x in tab) + { + il.Add(x.To(valueType)); + } + + { + list = il; + return true; + } + } + + list = null; + return false; + } + + private bool ConvertValueToMultiRankArray(Type type, out object multiRankArray) + { + if (type.IsArray) + { + var tab = List; + var rank = type.GetArrayRank(); + var dimensions = new int[rank]; + var dimCounter = tab; + for (var i = 0; i < rank; i++) + { + dimensions[i] = dimCounter.Count; + if (i != rank - 1) + { + dimCounter = dimCounter[0].List; + } + } + + var arr = Array.CreateInstance(type.GetElementType()!, dimensions); + + void BuildArray(Array array, params int[] idx) + { + var idxCopy = new int[idx.Length + 1]; + idx.CopyTo(idxCopy, 0); + if (idx.Length == rank - 1) + { + for (var i = 0; i < array.GetLength(idx.Length); i++) + { + idxCopy[idx.Length] = i; + array.SetValue(tab[i].To(type.GetElementType()), idxCopy); + } + } + else + { + for (var i = 0; i < array.GetLength(idx.Length); i++) + { + idxCopy[idx.Length] = i; + BuildArray(array, idxCopy); + } + } + } + + BuildArray(arr); + { + multiRankArray = arr; + return true; + } + } + + multiRankArray = null; + return false; + } + + private bool ConvertValueToSingleRankArray(Type type, out object singleRankArray) + { + if (type.IsArray && type.GetArrayRank() == 1) + { + var tab = List; + var arr = Array.CreateInstance(type.GetElementType()!, tab.Count); + for (var i = 0; i < tab.Count; i++) + { + arr.SetValue(tab[i].To(type.GetElementType()), i); + } + + { + singleRankArray = arr; + return true; + } + } + + singleRankArray = null; + return false; + } + + /// + /// Creates a Value from a + /// + /// The token to convert to a value + /// A value that represents the data stored in the token + public static DataValue FromJToken(JToken token) + { + if (token == null) return new DataValue(DataType.None); + while (true) + { + switch (token.Type) + { + case JTokenType.Property: + token = ((JProperty)token).Value; + continue; + case JTokenType.Null or JTokenType.None: + return new DataValue(DataType.None); + case JTokenType.Float: + return (double)token; + case JTokenType.Integer: + return (long)token; + case JTokenType.Boolean: + return (bool)token; + case JTokenType.Date or JTokenType.String: + return (string)token; + case JTokenType.Array: + return token.Select(FromJToken).ToList(); + case JTokenType.Object: + { + Dictionary values = new(); + foreach (var jToken in token) + { + var jProperty = (JProperty)jToken; + values[jProperty.Name] = FromJToken(jProperty.Value); + } + + return values; + } + default: + return new DataValue(DataType.None); + } + } + } + + /// + /// Converts a value to a json.net object + /// + /// A JToken that represents the data in this object + public JToken ToJToken() + { + if (IsBoolean) + { + return new JValue(Boolean); + } + + if (IsReal) + { + return new JValue(Real); + } + + if (IsInteger) + { + return new JValue(Integer); + } + + if (IsString) + { + return new JValue(String); + } + + if (IsList) + { + var array = new JArray(); + foreach (var value in List) + { + array.Add(value.ToJToken()); + } + return array; + } + + if (IsDictionary) + { + var obj = new JObject(); + foreach (var kvPair in Dictionary) + { + obj[kvPair.Key] = kvPair.Value.ToJToken(); + } + return obj; + } + + return null; + } + private static bool ConvertGenericListOrDictionaryToValue(object value, Type type, out DataValue listOrDictionaryDataValue) + { + switch (type.IsGenericType) + { + case true when type.GetGenericTypeDefinition() == typeof(Dictionary<,>): + { + var keyType = type.GetGenericArguments()[0]; + if (keyType != typeof(string)) + { + throw new TypeConversionException(type.FullName, "Value"); + } + + var dict = (IDictionary)value; + Dictionary newData = new(); + foreach (var k in dict.Keys) + { + var ks = (string)k; + newData[ks] = From(dict[k]); + } + + { + listOrDictionaryDataValue = newData; + return true; + } + } + case true when type.GetGenericTypeDefinition() == typeof(List<>): + { + listOrDictionaryDataValue = ((from object v in (IList)value select From(v)).ToList()); + return true; + } + } + + listOrDictionaryDataValue = null; + return false; + } + + private static bool ConvertMultiRankArrayToValue(object value, Type t, out DataValue multiRankArrayDataValue) + { + if (t.IsArray) + { + var a = (Array)value; + var outermostDimension = new List(); + + void TraverseRank(List containingDimension, Array arr, int r, params int[] idx) + { + var size = a.GetLength(r); + var idxCopy = new int[idx.Length + 1]; + idx.CopyTo(idxCopy, 0); + if (r == a.Rank - 1) + { + for (var i = 0; i < size; i++) + { + idxCopy[idx.Length] = i; + var v = arr.GetValue(idxCopy); + containingDimension.Add(From(v)); + } + } + else + { + for (var i = 0; i < size; i++) + { + idxCopy[idx.Length] = i; + var currentDimension = new List(); + TraverseRank(currentDimension, arr, r + 1, idxCopy); + outermostDimension.Add(currentDimension); + } + } + } + + + TraverseRank(outermostDimension, a, 0); + { + multiRankArrayDataValue = outermostDimension; + return true; + } + } + + multiRankArrayDataValue = null; + return false; + } + + private static bool ConvertSingleRankArrayToValue(object value, Type type, out DataValue singleRankArray) + { + if (type.IsArray && type.GetArrayRank() == 1) + { + var arr = (Array)value; + List vs = new List(); + foreach (var obj in arr) + { + vs.Add(From(obj)); + } + + { + singleRankArray = vs; + return true; + } + } + + singleRankArray = null; + return false; + } + public static DataValue From(object value) + { + switch (value) + { + case null: + return new DataValue(DataType.None); + case DataValue v: + return v; + case bool b: + return b; + case byte bv: + return bv; + case sbyte sbv: + return sbv; + case short sv: + return sv; + case ushort usv: + return usv; + case int iv: + return iv; + case uint uiv: + return uiv; + case long slv: + return slv; + case ulong ulv: + return ulv; + case float f: + return f; + case double d: + return d; + case string s: + return s; + case List lv: + return lv; + case DataValue[] av: + return av.ToList(); + case Dictionary dv: + return dv; + case PatchFunction pf: + return pf; + case Delegate d: + return new ManagedPatchFunction(d.Method, d.Target); + } + + var t = value.GetType(); + + if (ConvertSingleRankArrayToValue(value, t, out var singleRankArray)) return singleRankArray; + if (ConvertMultiRankArrayToValue(value, t, out var multiRankArrayValue)) return multiRankArrayValue; + if (ConvertGenericListOrDictionaryToValue(value, t, out var listOrDictionaryValue)) return listOrDictionaryValue; + Dictionary objectData = new(); + + + // Only store public data + foreach (var field in t.GetFields()) + { + objectData[field.Name] = From(field.GetValue(value)); + } + + return objectData; + } + + + public static readonly DataValue Null = new(DataType.None); + + public static bool operator ==(DataValue leftHandSide, DataValue rightHandSide) + { + if (ReferenceEquals(leftHandSide, null) || ReferenceEquals(rightHandSide, null)) + { + return ReferenceEquals(leftHandSide, rightHandSide); + } + + if (leftHandSide.Type != rightHandSide.Type) return false; + + if (leftHandSide.IsBoolean) + { + return leftHandSide.Boolean == rightHandSide.Boolean; + } + + if (leftHandSide.IsReal) + { + // ReSharper disable once CompareOfFloatsByEqualityOperator + return leftHandSide.Real == rightHandSide.Real; + } + + if (leftHandSide.IsInteger) + { + return leftHandSide.Integer == rightHandSide.Integer; + } + + if (leftHandSide.IsString) + { + return leftHandSide.String == rightHandSide.String; + } + + if (leftHandSide.IsList) + { + return ListCompare(leftHandSide.List,rightHandSide.List); + } + + if (leftHandSide.IsDictionary) + { + return DictionaryCompare(leftHandSide.Dictionary, rightHandSide.Dictionary); + } + + if (leftHandSide.IsClosure && rightHandSide.IsClosure) + { + return leftHandSide.Closure == rightHandSide.Closure; + } + + return true; + } + private static bool ListCompare(List leftHandSide, List rightHandSide) + { + if (leftHandSide.Count != rightHandSide.Count) + { + return false; + } + return !leftHandSide.Where((t, index) => t != rightHandSide[index]).Any(); + } + + private static bool DictionaryCompare(Dictionary leftHandSide, Dictionary rightHandSide) + { + if (leftHandSide.Count != rightHandSide.Count) + { + return false; + } + + foreach (var kv in leftHandSide) + { + if (rightHandSide.TryGetValue(kv.Key, out var rvalue)) + { + if (kv.Value != rvalue) + { + return false; + } + } + else + { + return false; + } + } + return true; + } + public static bool operator !=(DataValue a, DataValue b) => !(a == b); + + public override bool Equals(object obj) => this == (DataValue)obj; + + public override int GetHashCode() + { + if (IsNone || IsDeletion) + { + return 0; + } + + if (IsBoolean) + { + return Boolean.GetHashCode(); + } + + if (IsInteger) + { + return Integer.GetHashCode(); + } + + if (IsReal) + { + return Real.GetHashCode(); + } + + if (IsString) + { + return String.GetHashCode(); + } + + if (IsList) + { + return List.GetHashCode(); + } + + if (IsDictionary) + { + return Dictionary.GetHashCode(); + } + + if (IsClosure) + { + return Closure.GetHashCode(); + } + + return -1; + } + + public static DataValue operator +(DataValue leftHandSide, DataValue rightHandSide) + { + switch (leftHandSide.Type) + { + case DataType.Real when rightHandSide.IsReal: + return leftHandSide.Real + rightHandSide.Real; + case DataType.Real when rightHandSide.IsInteger: + return leftHandSide.Real + rightHandSide.Integer; + case DataType.Integer when rightHandSide.IsInteger: + return leftHandSide.Integer + rightHandSide.Integer; + case DataType.Integer when rightHandSide.IsReal: + return leftHandSide.Integer + rightHandSide.Real; + case DataType.String when rightHandSide.IsString: + return leftHandSide.String + rightHandSide.String; + case DataType.List when rightHandSide.IsList: + { + // If every value is immutable a shallow copy should be fine + var newList = new List(leftHandSide.List); + newList.AddRange(rightHandSide.List); + return newList; + } + case DataType.None: + case DataType.Boolean: + case DataType.Dictionary: + case DataType.Deletion: + case DataType.Closure: + default: + throw new DataValueOperationException($"Cannot add a {leftHandSide.Type} and a {rightHandSide.Type}"); + } + } + + public static DataValue operator -(DataValue leftHandSide, DataValue rightHandSide) + { + switch (leftHandSide.IsReal) + { + case true when rightHandSide.IsReal: + return leftHandSide.Real - rightHandSide.Real; + case true when rightHandSide.IsInteger: + return leftHandSide.Real - rightHandSide.Integer; + } + + switch (leftHandSide.IsInteger) + { + case true when rightHandSide.IsInteger: + return leftHandSide.Integer - rightHandSide.Integer; + case true when rightHandSide.IsReal: + return leftHandSide.Integer - rightHandSide.Real; + } + + if (leftHandSide.IsList && rightHandSide.IsList) + { + return leftHandSide.List.Where(x => rightHandSide.List.All(y => x != y)).ToList(); + } + + throw new DataValueOperationException($"Cannot subtract a {leftHandSide.Type} and a {rightHandSide.Type}"); + } + + private static DataValue StringRepeat(DataValue str, DataValue amount) + { + StringBuilder sb = new StringBuilder(); + for (var i = 0; i < amount.Integer; i++) + { + sb.Append(str.String); + } + + return sb.ToString(); + } + + private static DataValue ListRepeat(DataValue list, DataValue amount) + { + List newList = new() + { + Capacity = (int)(list.List.Count * amount.Integer) + }; + for (var i = 0; i < amount.Integer; i++) + { + newList.AddRange(list.List); + } + return newList; + } + + + public static DataValue operator *(DataValue leftHandSide, DataValue rightHandSide) + { + switch (leftHandSide.IsReal) + { + case true when rightHandSide.IsReal: + return leftHandSide.Real * rightHandSide.Real; + case true when rightHandSide.IsInteger: + return leftHandSide.Real * rightHandSide.Integer; + } + + switch (leftHandSide.IsInteger) + { + case true when rightHandSide.IsInteger: + return leftHandSide.Integer * rightHandSide.Integer; + case true when rightHandSide.IsReal: + return leftHandSide.Integer * rightHandSide.Real; + } + + if (leftHandSide.IsString && rightHandSide.IsInteger) + { + return StringRepeat(leftHandSide, rightHandSide); + } + + if (leftHandSide.IsInteger && rightHandSide.IsString) + { + return StringRepeat(rightHandSide, leftHandSide); + } + + if (leftHandSide.IsList && rightHandSide.IsInteger) + { + return ListRepeat(leftHandSide, rightHandSide); + } + + if (leftHandSide.IsInteger && rightHandSide.IsList) + { + return ListRepeat(rightHandSide, leftHandSide); + } + + throw new DataValueOperationException($"Cannot multiply a {leftHandSide.Type} and a {rightHandSide.Type}"); + } + + public static DataValue operator /(DataValue leftHandSide, DataValue rightHandSide) + { + if (leftHandSide.IsReal && rightHandSide.IsReal) + { + return leftHandSide.Real / rightHandSide.Real; + } + + switch (leftHandSide.IsInteger) + { + case true when rightHandSide.IsInteger: + return leftHandSide.Integer / rightHandSide.Integer; + case true when rightHandSide.IsReal: + return leftHandSide.Integer / rightHandSide.Real; + } + + if (leftHandSide.IsReal && rightHandSide.IsInteger) + { + return leftHandSide.Real / rightHandSide.Integer; + } + + throw new DataValueOperationException($"Cannot divide a {leftHandSide.Type} and a {rightHandSide.Type}"); + } + + public static bool operator >(DataValue leftHandSide, DataValue rightHandSide) + { + switch (leftHandSide.IsReal) + { + case true when rightHandSide.IsReal: + return leftHandSide.Real > rightHandSide.Real; + case true when rightHandSide.IsInteger: + return leftHandSide.Real > rightHandSide.Integer; + } + + switch (leftHandSide.IsInteger) + { + case true when rightHandSide.IsInteger: + return leftHandSide.Integer > rightHandSide.Integer; + case true when rightHandSide.IsReal: + return leftHandSide.Integer > rightHandSide.Real; + } + + if (leftHandSide.IsString && rightHandSide.IsString) + { + return string.Compare(leftHandSide.String, rightHandSide.String, StringComparison.Ordinal) > 0; + } + + throw new DataValueOperationException($"Cannot relationally compare a {leftHandSide.Type} and a {rightHandSide.Type}"); + } + + public static bool operator <(DataValue leftHandSide, DataValue rightHandSide) + { + switch (leftHandSide.IsReal) + { + case true when rightHandSide.IsReal: + return leftHandSide.Real < rightHandSide.Real; + case true when rightHandSide.IsInteger: + return leftHandSide.Real < rightHandSide.Integer; + } + + switch (leftHandSide.IsInteger) + { + case true when rightHandSide.IsInteger: + return leftHandSide.Integer < rightHandSide.Integer; + case true when rightHandSide.IsReal: + return leftHandSide.Integer < rightHandSide.Real; + } + + if (leftHandSide.IsString && rightHandSide.IsString) + { + return string.Compare(leftHandSide.String, rightHandSide.String, StringComparison.Ordinal) < 0; + } + + throw new DataValueOperationException($"Cannot relationally compare a {leftHandSide.Type} and a {rightHandSide.Type}"); + } + + public static bool operator >=(DataValue leftHandSide, DataValue rightHandSide) + { + switch (leftHandSide.IsReal) + { + case true when rightHandSide.IsReal: + return leftHandSide.Real >= rightHandSide.Real; + case true when rightHandSide.IsInteger: + return leftHandSide.Real >= rightHandSide.Integer; + } + + switch (leftHandSide.IsInteger) + { + case true when rightHandSide.IsInteger: + return leftHandSide.Integer >= rightHandSide.Integer; + case true when rightHandSide.IsReal: + return leftHandSide.Integer >= rightHandSide.Real; + } + + if (leftHandSide.IsString && rightHandSide.IsString) + { + return string.Compare(leftHandSide.String, rightHandSide.String, StringComparison.Ordinal) >= 0; + } + + throw new DataValueOperationException($"Cannot relationally compare a {leftHandSide.Type} and a {rightHandSide.Type}"); + } + + public static bool operator <=(DataValue leftHandSide, DataValue rightHandSide) + { + switch (leftHandSide.IsReal) + { + case true when rightHandSide.IsReal: + return leftHandSide.Real <= rightHandSide.Real; + case true when rightHandSide.IsInteger: + return leftHandSide.Real <= rightHandSide.Integer; + } + + switch (leftHandSide.IsInteger) + { + case true when rightHandSide.IsInteger: + return leftHandSide.Integer <= rightHandSide.Integer; + case true when rightHandSide.IsReal: + return leftHandSide.Integer <= rightHandSide.Real; + } + + if (leftHandSide.IsString && rightHandSide.IsString) + { + return string.Compare(leftHandSide.String, rightHandSide.String, StringComparison.Ordinal) <= 0; + } + + throw new DataValueOperationException($"Cannot relationally compare a {leftHandSide.Type} and a {rightHandSide.Type}"); + } + + public static DataValue operator %(DataValue leftHandSide, DataValue rightHandSide) => + leftHandSide.IsReal switch + { + true when rightHandSide.IsReal => leftHandSide.Real % rightHandSide.Real, + true when rightHandSide.IsInteger => leftHandSide.Real % rightHandSide.Integer, + _ => leftHandSide.IsInteger switch + { + true when rightHandSide.IsInteger => leftHandSide.Integer % rightHandSide.Integer, + true when rightHandSide.IsReal => leftHandSide.Integer % rightHandSide.Real, + _ => throw new DataValueOperationException( + $"Cannot take the remainder of a {leftHandSide.Type} and a {rightHandSide.Type}") + } + }; + + public static DataValue operator -(DataValue child) + { + if (child.IsInteger) + { + return -child.Integer; + } + + if (child.IsReal) + { + return -child.Real; + } + + throw new DataValueOperationException($"Cannot negate a {child.Type}"); + } + + public static bool operator !(DataValue child) => !child.Truthy; + + public static DataValue operator +(DataValue child) => child; + + public DataValue this[DataValue rightHandSide] + { + get + { + if (IsList && rightHandSide.IsInteger) + { + try + { + return List[(int)rightHandSide.Integer]; + } + catch + { + throw new IndexOutOfRangeException(((int)rightHandSide.Real) + " is out of range of the string being indexed"); + } + } + + if (IsString && rightHandSide.IsInteger) + { + try + { + return (int)String[(int)rightHandSide.Integer]; + } + catch + { + throw new IndexOutOfRangeException(rightHandSide.Integer + " is out of range of the string being indexed"); + } + } + + if (IsDictionary && rightHandSide.IsString) + { + try + { + return Dictionary[rightHandSide.String]; + } + catch + { + throw new KeyNotFoundException(rightHandSide.String + " is not a key found in the dictionary being indexed"); + } + } + + throw new DataValueOperationException( + $"Cannot subscript of a {Type} and a {rightHandSide.Type}"); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/DataValue.cs.meta b/Runtime/SassyPatching/DataValue.cs.meta new file mode 100644 index 0000000..2eafc98 --- /dev/null +++ b/Runtime/SassyPatching/DataValue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 77dbf662890b33043ac2c1e4f3b7c75c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions.meta b/Runtime/SassyPatching/Exceptions.meta new file mode 100644 index 0000000..8020597 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8258b65ae067f3e498706974be5c84e0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/BinaryExpressionTypeException.cs b/Runtime/SassyPatching/Exceptions/BinaryExpressionTypeException.cs new file mode 100644 index 0000000..db7f9ac --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/BinaryExpressionTypeException.cs @@ -0,0 +1,12 @@ +namespace PatchManager.SassyPatching.Exceptions +{ + /// + /// An exception thrown when the operands of a binary expression do not match together for the expression + /// + public class BinaryExpressionTypeException : InterpreterException + { + internal BinaryExpressionTypeException(Coordinate c, string operation, string firstType, string secondType) : base(c,$"Attempting to {operation} a value of type: {firstType} and a value of type: {secondType} which is not allowed") + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/BinaryExpressionTypeException.cs.meta b/Runtime/SassyPatching/Exceptions/BinaryExpressionTypeException.cs.meta new file mode 100644 index 0000000..f53f7ae --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/BinaryExpressionTypeException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 12830e06c14b9094ea52c8549a389b4c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/DataValueOperationException.cs b/Runtime/SassyPatching/Exceptions/DataValueOperationException.cs new file mode 100644 index 0000000..a8907b1 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/DataValueOperationException.cs @@ -0,0 +1,11 @@ +using System; + +namespace PatchManager.SassyPatching.Exceptions +{ + public class DataValueOperationException : Exception + { + public DataValueOperationException(string message) : base(message) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/DataValueOperationException.cs.meta b/Runtime/SassyPatching/Exceptions/DataValueOperationException.cs.meta new file mode 100644 index 0000000..ba5f39d --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/DataValueOperationException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b3311e6de41442545ad909b52dbb1704 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/DictionaryKeyNotFoundException.cs b/Runtime/SassyPatching/Exceptions/DictionaryKeyNotFoundException.cs new file mode 100644 index 0000000..0cd3bcf --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/DictionaryKeyNotFoundException.cs @@ -0,0 +1,12 @@ +namespace PatchManager.SassyPatching.Exceptions +{ + /// + /// An exception thrown when a dictionary is indexed with a key that it does not have + /// + public class DictionaryKeyNotFoundException : InterpreterException + { + internal DictionaryKeyNotFoundException(Coordinate coordinate, string message) : base(coordinate, message) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/DictionaryKeyNotFoundException.cs.meta b/Runtime/SassyPatching/Exceptions/DictionaryKeyNotFoundException.cs.meta new file mode 100644 index 0000000..b2c1311 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/DictionaryKeyNotFoundException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c7fb56be386e674482dc2cba29bc6a4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/FunctionReturnException.cs b/Runtime/SassyPatching/Exceptions/FunctionReturnException.cs new file mode 100644 index 0000000..ca4b466 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/FunctionReturnException.cs @@ -0,0 +1,14 @@ +using System; + +namespace PatchManager.SassyPatching.Exceptions +{ + internal class FunctionReturnException : Exception + { + internal DataValue FunctionResult; + + public FunctionReturnException(DataValue functionResult) + { + FunctionResult = functionResult; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/FunctionReturnException.cs.meta b/Runtime/SassyPatching/Exceptions/FunctionReturnException.cs.meta new file mode 100644 index 0000000..f252b2b --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/FunctionReturnException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ce98135f344d2d84eac74a0139845ef4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/ImportException.cs b/Runtime/SassyPatching/Exceptions/ImportException.cs new file mode 100644 index 0000000..07a3adb --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/ImportException.cs @@ -0,0 +1,9 @@ +using System; + +namespace PatchManager.SassyPatching.Exceptions +{ + internal class ImportException : Exception + { + + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/ImportException.cs.meta b/Runtime/SassyPatching/Exceptions/ImportException.cs.meta new file mode 100644 index 0000000..c356efe --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/ImportException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3f46246f555da3d49bb231bd619fdaf6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/IncorrectTypeException.cs b/Runtime/SassyPatching/Exceptions/IncorrectTypeException.cs new file mode 100644 index 0000000..6037941 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/IncorrectTypeException.cs @@ -0,0 +1,14 @@ +using System; + +namespace PatchManager.SassyPatching.Exceptions +{ + /// + /// An exception that is thrown when a is read as a type which it is not + /// + public class IncorrectTypeException : Exception + { + internal IncorrectTypeException(string message) : base(message) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/IncorrectTypeException.cs.meta b/Runtime/SassyPatching/Exceptions/IncorrectTypeException.cs.meta new file mode 100644 index 0000000..95388df --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/IncorrectTypeException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a299d5ec1860ef64fb870bf9116249e7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/InterpolationException.cs b/Runtime/SassyPatching/Exceptions/InterpolationException.cs new file mode 100644 index 0000000..83bc241 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/InterpolationException.cs @@ -0,0 +1,7 @@ +namespace PatchManager.SassyPatching.Exceptions +{ + public class InterpolationException : InterpreterException + { + internal InterpolationException(Coordinate coordinate, string message) : base(coordinate, message) { } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/InterpolationException.cs.meta b/Runtime/SassyPatching/Exceptions/InterpolationException.cs.meta new file mode 100644 index 0000000..c9a9453 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/InterpolationException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 37da1661d5ae6144e89cda2ded951bd4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/InterpreterException.cs b/Runtime/SassyPatching/Exceptions/InterpreterException.cs new file mode 100644 index 0000000..161e10d --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/InterpreterException.cs @@ -0,0 +1,20 @@ +using System; + +namespace PatchManager.SassyPatching.Exceptions +{ + /// + /// An exception thrown by the patch interpreter due to runtime code being bad + /// + public class InterpreterException : Exception + { + /// + /// The location of where the exception was thrown from + /// + public Coordinate Coordinate; + + internal InterpreterException(Coordinate coordinate, string message) : base($"{coordinate.ToString()}: {message}") + { + Coordinate = coordinate; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/InterpreterException.cs.meta b/Runtime/SassyPatching/Exceptions/InterpreterException.cs.meta new file mode 100644 index 0000000..5732e9a --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/InterpreterException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 691178b62d4f4be498fbb9d9b4049f53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/InvalidVariableReferenceException.cs b/Runtime/SassyPatching/Exceptions/InvalidVariableReferenceException.cs new file mode 100644 index 0000000..1d09195 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/InvalidVariableReferenceException.cs @@ -0,0 +1,12 @@ +namespace PatchManager.SassyPatching.Exceptions +{ + /// + /// An exception thrown when a variable is being referenced that does not exist + /// + public class InvalidVariableReferenceException : InterpreterException + { + internal InvalidVariableReferenceException(Coordinate coordinate, string message) : base(coordinate, message) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/InvalidVariableReferenceException.cs.meta b/Runtime/SassyPatching/Exceptions/InvalidVariableReferenceException.cs.meta new file mode 100644 index 0000000..a8fd288 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/InvalidVariableReferenceException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b51694660c3e0c49b2c3685a752f834 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/InvocationException.cs b/Runtime/SassyPatching/Exceptions/InvocationException.cs new file mode 100644 index 0000000..24d4051 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/InvocationException.cs @@ -0,0 +1,14 @@ +using System; + +namespace PatchManager.SassyPatching.Exceptions +{ + /// + /// Thrown when invoking a managed function goes awry + /// + public class InvocationException : Exception + { + internal InvocationException(string message) : base(message) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/InvocationException.cs.meta b/Runtime/SassyPatching/Exceptions/InvocationException.cs.meta new file mode 100644 index 0000000..97ca8ce --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/InvocationException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 21f735f974559494595f8169cb58cb37 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/ListIndexOutOfRangeException.cs b/Runtime/SassyPatching/Exceptions/ListIndexOutOfRangeException.cs new file mode 100644 index 0000000..4628ed7 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/ListIndexOutOfRangeException.cs @@ -0,0 +1,9 @@ +namespace PatchManager.SassyPatching.Exceptions +{ + public class ListIndexOutOfRangeException : InterpreterException + { + public ListIndexOutOfRangeException(Coordinate coordinate, string message) : base(coordinate, message) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/ListIndexOutOfRangeException.cs.meta b/Runtime/SassyPatching/Exceptions/ListIndexOutOfRangeException.cs.meta new file mode 100644 index 0000000..0207af5 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/ListIndexOutOfRangeException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 05282084ab6594343aab031d9ac8fd88 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/NotModifiableException.cs b/Runtime/SassyPatching/Exceptions/NotModifiableException.cs new file mode 100644 index 0000000..bc49d45 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/NotModifiableException.cs @@ -0,0 +1,15 @@ +using System; + +namespace PatchManager.SassyPatching.Exceptions +{ + /// + /// Thrown when a selectable is trying to be modified that can't be modified + /// + public class NotModifiableException : Exception + { + /// + public NotModifiableException(string message) : base(message) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/NotModifiableException.cs.meta b/Runtime/SassyPatching/Exceptions/NotModifiableException.cs.meta new file mode 100644 index 0000000..0acfe8e --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/NotModifiableException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 16307b6def7871147ae7ab6a0a57af39 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/TypeConversionException.cs b/Runtime/SassyPatching/Exceptions/TypeConversionException.cs new file mode 100644 index 0000000..3b4ca93 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/TypeConversionException.cs @@ -0,0 +1,14 @@ +using System; + +namespace PatchManager.SassyPatching.Exceptions +{ + /// + /// Thrown by the Managed invoker when a type cannot be converted either way + /// + public class TypeConversionException : Exception + { + public TypeConversionException(string from, string to) : base($"Cannot convert a value of type {from} to type {to}") + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/TypeConversionException.cs.meta b/Runtime/SassyPatching/Exceptions/TypeConversionException.cs.meta new file mode 100644 index 0000000..dd55dec --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/TypeConversionException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b6593240445b8194297a49f9b53e2131 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Exceptions/UnaryTypeException.cs b/Runtime/SassyPatching/Exceptions/UnaryTypeException.cs new file mode 100644 index 0000000..0acfdf3 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/UnaryTypeException.cs @@ -0,0 +1,12 @@ +namespace PatchManager.SassyPatching.Exceptions +{ + /// + /// An exception thrown when a unary expression is being run on a type that which it cannot + /// + public class UnaryTypeException : InterpreterException + { + internal UnaryTypeException(Coordinate coordinate, string operation, string firstType) : base(coordinate,$"Attempting to {operation} a value of type: {firstType} which is not allowed") + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Exceptions/UnaryTypeException.cs.meta b/Runtime/SassyPatching/Exceptions/UnaryTypeException.cs.meta new file mode 100644 index 0000000..47c3929 --- /dev/null +++ b/Runtime/SassyPatching/Exceptions/UnaryTypeException.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82415c539a196ac449dbd2e12f7fc3bb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution.meta b/Runtime/SassyPatching/Execution.meta new file mode 100644 index 0000000..945c176 --- /dev/null +++ b/Runtime/SassyPatching/Execution.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2a788f83f629b2349bc7d9cdf711c503 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/BoundPatchFunction.cs b/Runtime/SassyPatching/Execution/BoundPatchFunction.cs new file mode 100644 index 0000000..a7b789c --- /dev/null +++ b/Runtime/SassyPatching/Execution/BoundPatchFunction.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; + +namespace PatchManager.SassyPatching.Execution +{ + /// + /// A patch function that already has an argument bound to it + /// + public class BoundPatchFunction : PatchFunction + { + internal readonly PatchFunction InternalFunction; + internal readonly List LeftBindings; + internal readonly List RightBindings; + + internal BoundPatchFunction(PatchFunction internalFunction, List leftBindings, List rightBindings) + { + InternalFunction = internalFunction; + LeftBindings = leftBindings; + RightBindings = rightBindings; + } + + /// + public override DataValue Execute(Environment env, List arguments) + { + var newArgs = new List(LeftBindings); + newArgs.AddRange(arguments); + newArgs.AddRange(RightBindings); + return InternalFunction.Execute(env, newArgs); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/BoundPatchFunction.cs.meta b/Runtime/SassyPatching/Execution/BoundPatchFunction.cs.meta new file mode 100644 index 0000000..c407b4d --- /dev/null +++ b/Runtime/SassyPatching/Execution/BoundPatchFunction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: caf1dc0a797b5654db6a2416dd93b294 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/Environment.cs b/Runtime/SassyPatching/Execution/Environment.cs new file mode 100644 index 0000000..a1ab82c --- /dev/null +++ b/Runtime/SassyPatching/Execution/Environment.cs @@ -0,0 +1,97 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Nodes; +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; + +namespace PatchManager.SassyPatching.Execution +{ + /// + /// Describes a local environment/scope (per function/patch) used by the patching engine + /// + public class Environment + { + /// + /// The global environment that this environment is a part of + /// + public GlobalEnvironment GlobalEnvironment; + /// + /// The parent of this scope + /// + [CanBeNull] public readonly Environment Parent; + /// + /// The list of variables in this scope + /// + public Dictionary ScopedValues; + + + [CanBeNull] private List _slotActions; + + [CanBeNull] + public List SlotActions + { + get => _slotActions ?? Parent?.SlotActions; + set => _slotActions = value; + } + + /// + /// Creates a new environment + /// + /// The global environment that this environment will be a part of + /// The parent of the environment + public Environment(GlobalEnvironment globalEnvironment, [CanBeNull] Environment parent = null) + { + GlobalEnvironment = globalEnvironment; + Parent = parent; + ScopedValues = new Dictionary(); + } + + public DataValue this[string index] + { + get + { + if (ScopedValues.TryGetValue(index, out var result)) + { + return result; + } + + if (Parent != null) + { + return Parent[index]; + } + + throw new KeyNotFoundException(index); + } + set + { + if (value.IsDeletion) + { + if (ScopedValues.ContainsKey(index)) + { + ScopedValues.Remove(index); + } + + throw new KeyNotFoundException(index); + } + else + { + ScopedValues[index] = value; + } + } + } + + /// + /// Takes a "snapshot" of this environment, for later action taken within the environment, such as in selection actions + /// + /// A copy of this environment, in its current state, w/ each parent in their current state as well + public Environment Snapshot() + { + var scopedValues = new Dictionary(ScopedValues); + var parent = Parent?.Snapshot(); + return new Environment(GlobalEnvironment, parent) + { + ScopedValues = scopedValues, + _slotActions = _slotActions + }; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/Environment.cs.meta b/Runtime/SassyPatching/Execution/Environment.cs.meta new file mode 100644 index 0000000..6c08b4a --- /dev/null +++ b/Runtime/SassyPatching/Execution/Environment.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 496bb935c098c3f45a7168d3b35c253e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/GlobalEnvironment.cs b/Runtime/SassyPatching/Execution/GlobalEnvironment.cs new file mode 100644 index 0000000..ec88435 --- /dev/null +++ b/Runtime/SassyPatching/Execution/GlobalEnvironment.cs @@ -0,0 +1,74 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using UniLinq; + +namespace PatchManager.SassyPatching.Execution +{ + /// + /// Describes a global (per patch file) environment used by the sassy patching engine + /// + public class GlobalEnvironment + { + /// + /// This references the global state that all patches being run share + /// + public Universe Universe; + + /// + /// The Guid of the mod this patch file is from + /// + public string ModGuid; + + public List ImportedLibraries = new(); + + public Dictionary AllFunctions = new(); + + public Dictionary AllMixins = new(); + + + internal GlobalEnvironment(Universe universe, string modGuid) + { + Universe = universe; + ModGuid = modGuid; + } + + internal void Import(Environment rootEnvironment, string libraryName) + { + var fullyQualifiedLibraryName = libraryName.Contains(":") ? libraryName : $"{ModGuid}:{libraryName}"; + if (fullyQualifiedLibraryName.EndsWith(":*")) + { + var baseName = fullyQualifiedLibraryName.Replace(":*", ":"); + var anyFound = false; + foreach (var library in Universe.AllLibraries.Where(library => library.Key.StartsWith(baseName))) + { + anyFound = true; + if (ImportedLibraries.Contains(library.Key)) + { + continue; + } + + library.Value.RegisterInto(rootEnvironment); + ImportedLibraries.Add(library.Key); + } + + if (!anyFound) + { + throw new ImportException(); + } + } else + { + if (ImportedLibraries.Contains(fullyQualifiedLibraryName)) + return; + if (Universe.AllLibraries.TryGetValue(fullyQualifiedLibraryName, out var library)) + { + library.RegisterInto(rootEnvironment); + ImportedLibraries.Add(fullyQualifiedLibraryName); + } + else + { + throw new ImportException(); + } + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/GlobalEnvironment.cs.meta b/Runtime/SassyPatching/Execution/GlobalEnvironment.cs.meta new file mode 100644 index 0000000..0796814 --- /dev/null +++ b/Runtime/SassyPatching/Execution/GlobalEnvironment.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e445d9a52fc556b459139544f5e164c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/ManagedPatchFunction.cs b/Runtime/SassyPatching/Execution/ManagedPatchFunction.cs new file mode 100644 index 0000000..8078f92 --- /dev/null +++ b/Runtime/SassyPatching/Execution/ManagedPatchFunction.cs @@ -0,0 +1,156 @@ +using System.Collections.Generic; +using System.Reflection; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Exceptions; +using UniLinq; + +namespace PatchManager.SassyPatching.Execution +{ + internal class ManagedPatchFunction : PatchFunction + { + // private Func,Value> _execute; + private readonly MethodInfo _info; + private object? _target; + + public ManagedPatchFunction(MethodInfo info, object? target = null) + { + _info = info; + _target = target; + } + + private static object CheckParameter(ParameterInfo info, DataValue argument) + { + var obj = argument.To(info.ParameterType); + return obj; + } + + public override DataValue Execute(Environment env, List arguments) + { + List args = new(); + + // We are going to consume arguments as we go to prevent errors + + foreach (var parameter in _info.GetParameters()) + { + var argumentName = parameter.Name; + if (parameter.ParameterType.GetCustomAttribute() is { } attribute) + { + argumentName = attribute.ArgumentName; + } + + if (parameter.ParameterType == typeof(Environment)) + { + args.Add(env); + continue; + } + + if (parameter.ParameterType == typeof(GlobalEnvironment)) + { + args.Add(env.GlobalEnvironment); + continue; + } + + if (parameter.ParameterType == typeof(Universe)) + { + args.Add(env.GlobalEnvironment.Universe); + continue; + } + + if (parameter.ParameterType == typeof(List)) + { + args.Add(new List(arguments)); + arguments.Clear(); + continue; + } + + if (parameter.ParameterType == typeof(List) && + parameter.GetCustomAttributes().OfType().Any()) + { + var varArgs = new List(); + var remove = new List(); + for (var i = 0; i < arguments.Count; i++) + { + if (arguments[i].ArgumentName != null) continue; + varArgs.Add(arguments[i].ArgumentDataValue); + remove.Add(i); + } + + args.Add(varArgs); + for (var i = remove.Count - 1; i >= 0; i--) + { + arguments.RemoveAt(i); + } + continue; + } + + if (parameter.ParameterType == typeof(Dictionary) && + parameter.GetCustomAttributes().OfType().Any()) + { + var varArgs = new Dictionary(); + var remove = new List(); + for (var i = 0; i < arguments.Count; i++) + { + if (arguments[i].ArgumentName == null) continue; + varArgs.Add(arguments[i].ArgumentName, arguments[i].ArgumentDataValue); + remove.Add(i); + } + + args.Add(varArgs); + for (var i = remove.Count - 1; i >= 0; i--) + { + arguments.RemoveAt(i); + } + continue; + } + + bool foundPositional = false; + DataValue argument = null; + int removalIndex = -1; + for (int i = 0; i < arguments.Count; i++) + { + if (!foundPositional && arguments[i].ArgumentName == null) + { + foundPositional = true; + removalIndex = i; + argument = arguments[i].ArgumentDataValue; + } + + if (arguments[i].ArgumentName != argumentName) continue; + removalIndex = i; + argument = arguments[i].ArgumentDataValue; + break; + } + + if (removalIndex >= 0) + { + arguments.RemoveAt(removalIndex); + } + + if (argument == null) + { + if (parameter.HasDefaultValue) + { + args.Add(parameter.DefaultValue); + } + else + { + throw new InvocationException($"No value found for argument: {argumentName}"); + } + } + else + { + args.Add(CheckParameter(parameter, argument)); + } + + } + + if (arguments.Count > 0) + { + throw new InvocationException("Too many arguments passed"); + } + + return DataValue.From(_info.Invoke(_target, args.ToArray())); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/ManagedPatchFunction.cs.meta b/Runtime/SassyPatching/Execution/ManagedPatchFunction.cs.meta new file mode 100644 index 0000000..6945875 --- /dev/null +++ b/Runtime/SassyPatching/Execution/ManagedPatchFunction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6d8c5af0dbb01c444ae13c1031611263 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/ManagedPatchLibrary.cs b/Runtime/SassyPatching/Execution/ManagedPatchLibrary.cs new file mode 100644 index 0000000..e83fd2d --- /dev/null +++ b/Runtime/SassyPatching/Execution/ManagedPatchLibrary.cs @@ -0,0 +1,45 @@ +using System.Collections.Generic; +using System.Reflection; +using PatchManager.SassyPatching.Attributes; +using UniLinq; +using Unity.VisualScripting; + +namespace PatchManager.SassyPatching.Execution +{ + internal class ManagedPatchLibrary : PatchLibrary + { + private readonly Dictionary _functions; + private readonly Dictionary _constants; + + public ManagedPatchLibrary(IReflect libraryClass) + { + _functions = libraryClass.GetMethods(BindingFlags.Static | BindingFlags.Public) + .Where(method => method.GetCustomAttributes().OfType().Any()) + .ToDictionary(method => method.GetCustomAttributes().OfType().First().MethodName, + method => new ManagedPatchFunction(method)); + _constants = libraryClass.GetFields(BindingFlags.Static | BindingFlags.Public) + .Where(field => field.GetCustomAttributes().OfType().Any()).ToDictionary( + field => field.GetCustomAttributes().OfType().First().ConstantName, + field => DataValue.From(field.GetValue(null))); + _constants.AddRange(libraryClass.GetProperties(BindingFlags.Static | BindingFlags.Public) + .Where(property => property.GetCustomAttributes().OfType().Any()).ToDictionary( + property => property.GetCustomAttributes().OfType().First().ConstantName, + property => DataValue.From(property.GetValue(null)))); + } + + public override void RegisterInto(Environment environment) + { + foreach (var function in _functions) + { + environment.GlobalEnvironment.Universe.MessageLogger($"Registering function: {function.Key}"); + environment.GlobalEnvironment.AllFunctions[function.Key] = function.Value; + } + + foreach (var constant in _constants) + { + environment.GlobalEnvironment.Universe.MessageLogger($"Registering constant: {constant.Key}"); + environment[constant.Key] = constant.Value; + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/ManagedPatchLibrary.cs.meta b/Runtime/SassyPatching/Execution/ManagedPatchLibrary.cs.meta new file mode 100644 index 0000000..622f6b6 --- /dev/null +++ b/Runtime/SassyPatching/Execution/ManagedPatchLibrary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c1265c80a4a6ac64fac9e9bf472f5ee4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/PatchArgument.cs b/Runtime/SassyPatching/Execution/PatchArgument.cs new file mode 100644 index 0000000..a07ac49 --- /dev/null +++ b/Runtime/SassyPatching/Execution/PatchArgument.cs @@ -0,0 +1,20 @@ +using JetBrains.Annotations; + +namespace PatchManager.SassyPatching.Execution +{ + /// + /// This represents an argument passed to a patch function + /// + [PublicAPI] + public class PatchArgument + { + /// + /// The name of the argument if it was named by the caller + /// + [CanBeNull] public string ArgumentName; + /// + /// The value of the argument + /// + public DataValue ArgumentDataValue; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/PatchArgument.cs.meta b/Runtime/SassyPatching/Execution/PatchArgument.cs.meta new file mode 100644 index 0000000..3c841b6 --- /dev/null +++ b/Runtime/SassyPatching/Execution/PatchArgument.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ec2b687883d71954386943c96debed5f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/PatchFunction.cs b/Runtime/SassyPatching/Execution/PatchFunction.cs new file mode 100644 index 0000000..68b2f12 --- /dev/null +++ b/Runtime/SassyPatching/Execution/PatchFunction.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; + +namespace PatchManager.SassyPatching.Execution +{ + /// + /// This is the base class for a patcher function be it dll or file based + /// + public abstract class PatchFunction + { + /// + /// Execute this function + /// + /// The environment this function is being executed in (used mostly for DLL based functions) + /// The list of arguments for the function, the name can be null + /// + public abstract DataValue Execute(Environment env, List arguments); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/PatchFunction.cs.meta b/Runtime/SassyPatching/Execution/PatchFunction.cs.meta new file mode 100644 index 0000000..71995c1 --- /dev/null +++ b/Runtime/SassyPatching/Execution/PatchFunction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4baf7332fbd91214993493a6a46c512c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/PatchLibrary.cs b/Runtime/SassyPatching/Execution/PatchLibrary.cs new file mode 100644 index 0000000..689b3d2 --- /dev/null +++ b/Runtime/SassyPatching/Execution/PatchLibrary.cs @@ -0,0 +1,14 @@ +namespace PatchManager.SassyPatching.Execution +{ + /// + /// This is the base class of a patcher library, either for file or dll libraries, the register into is what is used by the engine to register everything + /// + public abstract class PatchLibrary + { + /// + /// Register this library into an environment + /// + /// The environment to register it into + public abstract void RegisterInto(Environment environment); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/PatchLibrary.cs.meta b/Runtime/SassyPatching/Execution/PatchLibrary.cs.meta new file mode 100644 index 0000000..fbe1b32 --- /dev/null +++ b/Runtime/SassyPatching/Execution/PatchLibrary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f7caa3f62b78fe041ab5924eb9b4b7f3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/PatchMixin.cs b/Runtime/SassyPatching/Execution/PatchMixin.cs new file mode 100644 index 0000000..e2262a8 --- /dev/null +++ b/Runtime/SassyPatching/Execution/PatchMixin.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Nodes; +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; +using PatchManager.SassyPatching.Nodes.Statements.TopLevel; + +namespace PatchManager.SassyPatching.Execution +{ + public class PatchMixin + { + public Mixin Function; + + public PatchMixin(Mixin mixin) + { + Function = mixin; + } + + public void Include(Environment env, List arguments, ISelectable selectable, [CanBeNull] IModifiable modifiable) + { + var subEnvironment = new Environment(env.GlobalEnvironment, env); + foreach (var arg in Function.Arguments) + { + ConsumeMixinArgument(arguments, arg, subEnvironment); + } + + if (arguments.Count > 0) + { + throw new InvocationException("Too many arguments have been passed"); + } + foreach (var body in Function.Body) + { + if (body is ISelectionAction selectionAction) + { + selectionAction.ExecuteOn(subEnvironment, selectable, modifiable); + } + else + { + body.ExecuteIn(subEnvironment); + } + } + + } + + private static void ConsumeMixinArgument(List arguments, Argument arg, Environment subEnvironment) + { + // As per usual we consume + var foundPositional = false; + DataValue argument = null; + var removalIndex = -1; + for (var i = 0; i < arguments.Count; i++) + { + if (!foundPositional && arguments[i].ArgumentName == null) + { + foundPositional = true; + removalIndex = i; + argument = arguments[i].ArgumentDataValue; + } + + if (arguments[i].ArgumentName != arg.Name) continue; + removalIndex = i; + argument = arguments[i].ArgumentDataValue; + break; + } + + if (removalIndex >= 0) + { + arguments.RemoveAt(removalIndex); + } + if (argument == null) + { + if (arg.Value != null) + { + subEnvironment[arg.Name] = arg.Value.Compute(subEnvironment); + } + else + { + throw new InvocationException($"No value found for argument: {arg.Name}"); + } + } + else + { + // args.Add(CheckParameter(parameter, argument)); + subEnvironment[arg.Name] = argument; + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/PatchMixin.cs.meta b/Runtime/SassyPatching/Execution/PatchMixin.cs.meta new file mode 100644 index 0000000..d781c6e --- /dev/null +++ b/Runtime/SassyPatching/Execution/PatchMixin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f8e60f3851cccb042acc42014c6d749a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/SassyGenerator.cs b/Runtime/SassyPatching/Execution/SassyGenerator.cs new file mode 100644 index 0000000..415df6c --- /dev/null +++ b/Runtime/SassyPatching/Execution/SassyGenerator.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Nodes.Attributes; +using PatchManager.SassyPatching.Nodes.Statements; +using PatchManager.Shared.Interfaces; +using UniLinq; + +namespace PatchManager.SassyPatching.Execution +{ + public class SassyGenerator : ITextAssetGenerator + {// This is a snapshot of the environment before the patch was registered, note it will still reference the same global environment as its file, as that is only mutated by function declarations + // Same w/ universe environment, as that should only contain stage definitions and such + private Environment _environmentSnapshot; + private SelectionBlock _rootSelectionBlock; + private List _arguments; + + internal SassyGenerator(Environment environmentSnapshot, SelectionBlock rootSelectionBlock, List arguments) + { + _environmentSnapshot = environmentSnapshot; + _rootSelectionBlock = rootSelectionBlock; + _arguments = arguments; + var stage = rootSelectionBlock.Attributes.OfType().FirstOrDefault(); + if (stage == null) + { + Priority = ulong.MaxValue; + } + else + { + var global = environmentSnapshot.GlobalEnvironment; + string stageName; + if (stage.Stage.Contains(':')) + { + stageName = stage.Stage; + } + else + { + stageName = global.ModGuid + ":" + stage.Stage; + } + + // If this errors then we don't register the patch, but we should give a more friendly thing to this at some point + Priority = global.Universe.AllStages[stageName]; + } + } + + /// + public ulong Priority { get; } + public string Create(out string label, out string name) + { + var val = _rootSelectionBlock.ExecuteCreation(_environmentSnapshot, _arguments); + label = val.Label; + name = val.Name; + return val.Text; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/SassyGenerator.cs.meta b/Runtime/SassyPatching/Execution/SassyGenerator.cs.meta new file mode 100644 index 0000000..ecabec0 --- /dev/null +++ b/Runtime/SassyPatching/Execution/SassyGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0fdf70fcb1756b9459c4fd5ec6d5455e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/SassyPatchClosure.cs b/Runtime/SassyPatching/Execution/SassyPatchClosure.cs new file mode 100644 index 0000000..5fa8fd5 --- /dev/null +++ b/Runtime/SassyPatching/Execution/SassyPatchClosure.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Nodes.Expressions; + +namespace PatchManager.SassyPatching.Execution +{ + internal class SassyPatchClosure : PatchFunction + { + public Environment Snapshot; + public Closure Function; + + public SassyPatchClosure(Environment snapshot, Closure function) + { + Snapshot = snapshot; + Function = function; + } + + public override DataValue Execute(Environment env, List arguments) + { + Environment subEnvironment = new Environment(Snapshot.GlobalEnvironment, Snapshot); + foreach (var arg in Function.Arguments) + { + // As per usual we consume + bool foundPositional = false; + DataValue argument = null; + int removalIndex = -1; + for (int i = 0; i < arguments.Count; i++) + { + if (!foundPositional && arguments[i].ArgumentName == null) + { + foundPositional = true; + removalIndex = i; + argument = arguments[i].ArgumentDataValue; + } + + if (arguments[i].ArgumentName != arg.Name) continue; + removalIndex = i; + argument = arguments[i].ArgumentDataValue; + break; + } + + if (removalIndex >= 0) + { + arguments.RemoveAt(removalIndex); + } + if (argument == null) + { + if (arg.Value != null) + { + subEnvironment[arg.Name] = arg.Value.Compute(subEnvironment); + } + else + { + throw new InvocationException($"No value found for argument: {arg.Name}"); + } + } + else + { + // args.Add(CheckParameter(parameter, argument)); + subEnvironment[arg.Name] = argument; + } + } + + if (arguments.Count > 0) + { + throw new InvocationException("Too many arguments have been passed"); + } + try + { + foreach (var body in Function.Body) + { + body.ExecuteIn(subEnvironment); + } + } + catch (FunctionReturnException ret) + { + return ret.FunctionResult; + } + + return new DataValue(DataValue.DataType.None); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/SassyPatchClosure.cs.meta b/Runtime/SassyPatching/Execution/SassyPatchClosure.cs.meta new file mode 100644 index 0000000..b7e05bc --- /dev/null +++ b/Runtime/SassyPatching/Execution/SassyPatchClosure.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 302c1e4549cb8d749944ae6e08a7d54e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/SassyPatchFunction.cs b/Runtime/SassyPatching/Execution/SassyPatchFunction.cs new file mode 100644 index 0000000..27577a7 --- /dev/null +++ b/Runtime/SassyPatching/Execution/SassyPatchFunction.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Nodes.Statements.TopLevel; + +namespace PatchManager.SassyPatching.Execution +{ + internal class SassyPatchFunction : PatchFunction + { + public Environment Snapshot; + public Function Function; + + public SassyPatchFunction(Environment snapshot, Function function) + { + Snapshot = snapshot; + Function = function; + } + + public override DataValue Execute(Environment env, List arguments) + { + Environment subEnvironment = new Environment(Snapshot.GlobalEnvironment, Snapshot); + foreach (var arg in Function.Arguments) + { + // As per usual we consume + bool foundPositional = false; + DataValue argument = null; + int removalIndex = -1; + for (int i = 0; i < arguments.Count; i++) + { + if (!foundPositional && arguments[i].ArgumentName == null) + { + foundPositional = true; + removalIndex = i; + argument = arguments[i].ArgumentDataValue; + } + + if (arguments[i].ArgumentName != arg.Name) continue; + removalIndex = i; + argument = arguments[i].ArgumentDataValue; + break; + } + + if (removalIndex >= 0) + { + arguments.RemoveAt(removalIndex); + } + if (argument == null) + { + if (arg.Value != null) + { + subEnvironment[arg.Name] = arg.Value.Compute(subEnvironment); + } + else + { + throw new InvocationException($"No value found for argument: {arg.Name}"); + } + } + else + { + // args.Add(CheckParameter(parameter, argument)); + subEnvironment[arg.Name] = argument; + } + } + + if (arguments.Count > 0) + { + throw new InvocationException("Too many arguments have been passed"); + } + try + { + foreach (var body in Function.Body) + { + body.ExecuteIn(subEnvironment); + } + } + catch (FunctionReturnException ret) + { + return ret.FunctionResult; + } + + return new DataValue(DataValue.DataType.None); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/SassyPatchFunction.cs.meta b/Runtime/SassyPatching/Execution/SassyPatchFunction.cs.meta new file mode 100644 index 0000000..3cd49a8 --- /dev/null +++ b/Runtime/SassyPatching/Execution/SassyPatchFunction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 46b8f50b6869fb9468e90f1a0cbe2892 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/SassyPatchLibrary.cs b/Runtime/SassyPatching/Execution/SassyPatchLibrary.cs new file mode 100644 index 0000000..08d3e0f --- /dev/null +++ b/Runtime/SassyPatching/Execution/SassyPatchLibrary.cs @@ -0,0 +1,19 @@ +using PatchManager.SassyPatching.Nodes; + +namespace PatchManager.SassyPatching.Execution +{ + internal class SassyPatchLibrary : PatchLibrary + { + public SassyPatch Patch; + + public SassyPatchLibrary(SassyPatch patch) + { + Patch = patch; + } + + public override void RegisterInto(Environment environment) + { + Patch.ExecuteIn(environment); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/SassyPatchLibrary.cs.meta b/Runtime/SassyPatching/Execution/SassyPatchLibrary.cs.meta new file mode 100644 index 0000000..607d3dd --- /dev/null +++ b/Runtime/SassyPatching/Execution/SassyPatchLibrary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 61af288d61845014f8e0e35a361daad2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/SassyTextPatcher.cs b/Runtime/SassyPatching/Execution/SassyTextPatcher.cs new file mode 100644 index 0000000..344febf --- /dev/null +++ b/Runtime/SassyPatching/Execution/SassyTextPatcher.cs @@ -0,0 +1,65 @@ +using PatchManager.SassyPatching.Nodes.Attributes; +using PatchManager.SassyPatching.Nodes.Statements; +using PatchManager.SassyPatching.Utility; +using PatchManager.Shared.Interfaces; +using UniLinq; + +namespace PatchManager.SassyPatching.Execution +{ + /// + /// This is the class that all sassy patches get converted to + /// + public class SassyTextPatcher : ITextPatcher + { + + // This is a snapshot of the environment before the patch was registered, note it will still reference the same global environment as its file, as that is only mutated by function declarations + // Same w/ universe environment, as that should only contain stage definitions and such + private Environment _environmentSnapshot; + private SelectionBlock _rootSelectionBlock; + + internal SassyTextPatcher(Environment environmentSnapshot, SelectionBlock rootSelectionBlock) + { + _environmentSnapshot = environmentSnapshot; + _rootSelectionBlock = rootSelectionBlock; + // var stage = rootSelectionBlock.Attributes.OfType().FirstOrDefault(); + // if (stage == null) + // { + // Priority = ulong.MaxValue; + // } + // else + // { + // var global = environmentSnapshot.GlobalEnvironment; + // string stageName; + // if (stage.Stage.Contains(':')) + // { + // stageName = stage.Stage; + // } + // else + // { + // stageName = global.ModGuid + ":" + stage.Stage; + // } + // + // // If this errors then we don't register the patch, but we should give a more friendly thing to this at some point + // Priority = global.Universe.AllStages[stageName]; + // } + OriginalGuid = environmentSnapshot.GlobalEnvironment.ModGuid; + PriorityString = + rootSelectionBlock.Attributes.OfType().FirstOrDefault() is { } runAtStageAttribute + ? runAtStageAttribute.Stage.Interpolate(environmentSnapshot) + : environmentSnapshot.GlobalEnvironment.ModGuid; + + } + + public string OriginalGuid { get; } + public string PriorityString { get; } + + /// + public ulong Priority { get; set; } + + /// + public bool TryPatch(string patchType, string name, ref string patchData) + { + return _rootSelectionBlock.ExecuteFresh(_environmentSnapshot,patchType, name, ref patchData); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/SassyTextPatcher.cs.meta b/Runtime/SassyPatching/Execution/SassyTextPatcher.cs.meta new file mode 100644 index 0000000..8c354c0 --- /dev/null +++ b/Runtime/SassyPatching/Execution/SassyTextPatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b709a910bd733f244be736b4a81e688e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/SelectableWithEnvironment.cs b/Runtime/SassyPatching/Execution/SelectableWithEnvironment.cs new file mode 100644 index 0000000..ffb6c36 --- /dev/null +++ b/Runtime/SassyPatching/Execution/SelectableWithEnvironment.cs @@ -0,0 +1,20 @@ +using PatchManager.SassyPatching.Interfaces; + +namespace PatchManager.SassyPatching.Execution +{ + /// + /// Used to store information in a selectable, for stuff like class capture selectors and the like + /// Makes stuff a lot more complex, but meh + /// + public class SelectableWithEnvironment + { + /// + /// The selectable being selected against + /// + public ISelectable Selectable; + /// + /// The environment being used + /// + public Environment Environment; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/SelectableWithEnvironment.cs.meta b/Runtime/SassyPatching/Execution/SelectableWithEnvironment.cs.meta new file mode 100644 index 0000000..bd2f49b --- /dev/null +++ b/Runtime/SassyPatching/Execution/SelectableWithEnvironment.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f5f54764556f38b46af9bf556c25e726 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/Stage.cs b/Runtime/SassyPatching/Execution/Stage.cs new file mode 100644 index 0000000..4e910ac --- /dev/null +++ b/Runtime/SassyPatching/Execution/Stage.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using UniLinq; + +namespace PatchManager.SassyPatching.Execution +{ + public class Stage + { + public List RunsBefore = new(); + public List RunsAfter = new(); + + + public void UpdateRequirements(List allStages) + { + RunsBefore = RunsBefore.Where(x => allStages.Contains(x)).ToList(); + RunsAfter = RunsAfter.Where(x => allStages.Contains(x)).ToList(); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/Stage.cs.meta b/Runtime/SassyPatching/Execution/Stage.cs.meta new file mode 100644 index 0000000..1541128 --- /dev/null +++ b/Runtime/SassyPatching/Execution/Stage.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 683f5ab5390921140bed78daa3e81996 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Execution/Universe.cs b/Runtime/SassyPatching/Execution/Universe.cs new file mode 100644 index 0000000..2c78292 --- /dev/null +++ b/Runtime/SassyPatching/Execution/Universe.cs @@ -0,0 +1,552 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Antlr4.Runtime; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Nodes; +using PatchManager.Shared.Interfaces; +using SassyPatchGrammar; +using System.Reflection; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Nodes.Expressions; +using PatchManager.SassyPatching.Utility; +using PatchManager.Shared; +using UniLinq; +using Unity.VisualScripting; +using UnityEngine; + +namespace PatchManager.SassyPatching.Execution +{ + /// + /// The state that all executing patches share + /// + public class Universe + { + /// + /// This contains all rule sets that have been found in all assemblies + /// + public static readonly Dictionary RuleSets; + + /// + /// This contains all the managed libraries that have been found in all assemblies + /// + public static readonly Dictionary AllManagedLibraries; + + + /// + /// This contains all the constant text based libraries that have been registered + /// + public static readonly Dictionary AllRawLibraries = new(); + + private static List _preloadedLabels; + + static Universe() + { + RuleSets = new(); + AllManagedLibraries = new(); + _preloadedLabels = new(); + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + // Only use public rule sets + foreach (var type in assembly.GetTypes()) + { + if (type.IsAbstract || type.IsInterface) continue; + if (typeof(IPatcherRuleSet).IsAssignableFrom(type)) + { + var rsAttribute = type.GetCustomAttribute(); + if (rsAttribute != null) + { + RuleSets[rsAttribute.RulesetName] = (IPatcherRuleSet)Activator.CreateInstance(type); + _preloadedLabels.AddRange(rsAttribute.PreloadLabels); + } + } + + var sassyLibraryAttribute = type.GetCustomAttribute(); + if (sassyLibraryAttribute != null) + { + var name = sassyLibraryAttribute.Mod + ":" + sassyLibraryAttribute.Library; + AllManagedLibraries[name] = new ManagedPatchLibrary(type); + Console.WriteLine($"Registered a managed library, {name}"); + } + } + } + } + + + public Dictionary> Configs = new(); +#nullable enable + public List<(long priority, string label, string? name, Expression updateExpression, Environment snapshot)> ConfigUpdates = new(); + public void AddConfigUpdater(long priority, string label, string? name, Expression updateExpression, Environment snapshot) + { + if (ConfigUpdates.Count == 0) + { + ConfigUpdates.Add((priority, label, name, updateExpression,snapshot)); + return; + } + + for (var i = 0; i < ConfigUpdates.Count; i++) + { + if (ConfigUpdates[i].priority < priority) continue; + + ConfigUpdates.Insert(i,(priority, label, name, updateExpression,snapshot)); + return; + } + ConfigUpdates.Add((priority, label, name, updateExpression,snapshot)); + } +#nullable disable + /// + /// All stages defined by every mod + /// + public Dictionary AllStages = new(); + + // Populated from Space Warps mod list come 1.3.0 + public List AllMods; + + /// + /// This is an action that is taken + /// + public readonly Action RegisterPatcher; + + + /// + /// Register a generator patch + /// + public readonly Action RegisterGenerator; + + /// + /// This logs errors in this universe + /// + public readonly Action ErrorLogger; + + + /// + /// The list of labels that this universe needs loaded to respond to + /// + public List LoadedLabels; + + /// + /// This logs any message that is not an error in the universe + /// + public readonly Action MessageLogger; + + private readonly List<(string id, SassyPatch patch)> _toRegister = new(); + + /// + /// Create a new universal state + /// + /// This action receives patchers and registers them for later execution + /// The action to be taken to log an error + /// The action to be taken to log a message + public Universe(Action registerPatcher, Action errorLogger, Action messageLogger, Action registerGenerator, List allMods) + { + RegisterPatcher = registerPatcher; + ErrorLogger = errorLogger; + MessageLogger = messageLogger; + RegisterGenerator = registerGenerator; + LoadedLabels = new List(_preloadedLabels); + AllMods = allMods; + MessageLogger("Setup universe!"); + SetupBasePriorities(allMods); + LoadAllRawPatches(); + } + + // TODO: Fix this so that other mods stages get their guids working + /// + /// All the libraries in this "universe" + /// + public readonly Dictionary AllLibraries = new(AllManagedLibraries); + + private class LoadException : Exception + { + public LoadException(string message) : base(message) + { + } + } + + internal class ParserListener : IAntlrErrorListener + { + internal bool Errored; + internal Action ErrorLogger; + internal string File; + internal ParserListener(string file, Action errorLogger) + { + File = file; + ErrorLogger = errorLogger; + } + + public void SyntaxError(TextWriter output, IRecognizer recognizer, IToken offendingSymbol, int line, + int charPositionInLine, + string msg, RecognitionException e) + { + Errored = true; + ErrorLogger.Invoke($"error parsing {File} - {line}:{charPositionInLine}: {msg}"); + } + } + + internal class LexerListener : IAntlrErrorListener + { + internal bool Errored; + internal Action ErrorLogger; + internal string File; + internal LexerListener(string file, Action errorLogger) + { + File = file; + ErrorLogger = errorLogger; + } + + public void SyntaxError(TextWriter output, IRecognizer recognizer, int offendingSymbol, int line, + int charPositionInLine, + string msg, RecognitionException e) + { + Errored = true; + ErrorLogger.Invoke($"error lexing {File} - {line}:{charPositionInLine}: {msg}"); + } + } + + private void LoadAllRawPatches() + { + var tokenTransformer = new Transformer(msg => throw new LoadException(msg)); + foreach (var (id, raw) in AllRawLibraries) + { + try + { + MessageLogger.Invoke($"Loading library {id}"); + var charStream = CharStreams.fromString(raw); + var lexerErrorGenerator = new LexerListener(id, ErrorLogger); + var lexer = new sassy_lexer(charStream); + lexer.AddErrorListener(lexerErrorGenerator); + if (lexerErrorGenerator.Errored) + throw new LoadException("lexer errors detected"); + var tokenStream = new CommonTokenStream(lexer); + var parser = new sassy_parser(tokenStream); + var parserErrorGenerator = new ParserListener(id, ErrorLogger); + parser.AddErrorListener(parserErrorGenerator); + if (parserErrorGenerator.Errored) + throw new LoadException("parser errors detected"); + var patchContext = parser.patch(); + tokenTransformer.Errored = false; + var patch = tokenTransformer.Visit(patchContext) as SassyPatch; + var lib = new SassyPatchLibrary(patch); + AllLibraries[id] = lib; + } + catch (Exception e) + { + ErrorLogger($"Could not load library: {id} due to: {e.Message}"); + } + } + } + + /// + /// Loads all patches from a directory + /// + /// + /// The ID of the mod to load the guid as + public void LoadPatchesInDirectory(DirectoryInfo directory, string modId) + { + // MessageLogger.Invoke($"Loading patches from {directory} (modId: {modId})"); + var tokenTransformer = new Transformer(msg => throw new LoadException(msg)); + foreach (var library in directory.EnumerateFiles("_*.patch", SearchOption.AllDirectories)) + { + LoadSingleLibrary(modId, library.Name, CharStreams.fromPath(library.FullName), tokenTransformer); + } + + foreach (var patch in directory.EnumerateFiles("*.patch", SearchOption.AllDirectories)) + { + LoadSinglePatch(modId, patch.Name, CharStreams.fromPath(patch.FullName), tokenTransformer); + } + } + + /// + /// Loads a single patch + /// + /// The file info of the patch file + /// The working directory to generate the patch mod id against + public void LoadSinglePatchFile(FileInfo patch, DirectoryInfo cwd) + { + var tokenTransformer = new Transformer(msg => throw new LoadException(msg)); + var name = Path.GetFileNameWithoutExtension(patch.FullName); + var id = patch.Directory!.FullName.MakeRelativePathTo(cwd.FullName).Replace("\\", "-"); + if (name.StartsWith("_")) + { + LoadSingleLibrary(id, name, CharStreams.fromPath(patch.FullName), tokenTransformer); + } + else + { + LoadSinglePatch(id, name, CharStreams.fromPath(patch.FullName), tokenTransformer); + } + } + + /// + /// Loads a single patch + /// + /// The text asset to load + /// Mod ID + public void LoadPatchAsset(TextAsset asset, string modId) + { + var tokenTransformer = new Transformer(msg => throw new LoadException(msg)); + if (asset.name.StartsWith("_")) + { + LoadSingleLibrary(modId, asset.name, CharStreams.fromString(asset.text), tokenTransformer); + } + else + { + LoadSinglePatch(modId, asset.name, CharStreams.fromString(asset.text), tokenTransformer); + } + } + + private void LoadSinglePatch(string modId, string name, ICharStream charStream, Transformer tokenTransformer) + { + if (name.StartsWith("_")) + { + return; + } + + try + { + MessageLogger.Invoke($"Loading patch {modId}:{name}"); + var lexer = new sassy_lexer(charStream); + var lexerErrorGenerator = new LexerListener($"{modId}:{name}", ErrorLogger); + lexer.AddErrorListener(lexerErrorGenerator); + if (lexerErrorGenerator.Errored) + { + throw new LoadException("lexer errors detected"); + } + + var tokenStream = new CommonTokenStream(lexer); + var parser = new sassy_parser(tokenStream); + var parserErrorGenerator = new ParserListener($"{modId}:{name}", ErrorLogger); + parser.AddErrorListener(parserErrorGenerator); + var patchContext = parser.patch(); + if (parserErrorGenerator.Errored) + { + throw new LoadException("parser errors detected"); + } + + tokenTransformer.Errored = false; + // var gEnv = new GlobalEnvironment(this, modId); + // var env = new Environment(gEnv); + var ctx = tokenTransformer.Visit(patchContext) as SassyPatch; + _toRegister.Add((modId, ctx)); + // lib = new SassyPatchLibrary(patch); + } + catch (Exception e) + { + ErrorLogger($"Could not run patch: {modId}:{name} due to: {e}"); + } + } + + private void LoadSingleLibrary(string modId, string name, ICharStream charStream, Transformer tokenTransformer) + { + string libName = modId + ":" + name.Replace(".patch", "").TrimFirst(); + try + { + MessageLogger.Invoke($"Loading library {libName}"); + var lexerErrorGenerator = new LexerListener(libName, ErrorLogger); + var lexer = new sassy_lexer(charStream); + lexer.AddErrorListener(lexerErrorGenerator); + if (lexerErrorGenerator.Errored) + { + throw new LoadException("lexer errors detected"); + } + + var tokenStream = new CommonTokenStream(lexer); + var parser = new sassy_parser(tokenStream); + var parserErrorGenerator = new ParserListener(libName, ErrorLogger); + parser.AddErrorListener(parserErrorGenerator); + if (parserErrorGenerator.Errored) + { + throw new LoadException("parser errors detected"); + } + + var patchContext = parser.patch(); + tokenTransformer.Errored = false; + var patch = tokenTransformer.Visit(patchContext) as SassyPatch; + var lib = new SassyPatchLibrary(patch); + AllLibraries[libName] = lib; + } + catch (Exception e) + { + ErrorLogger($"Could not load library: {libName} due to: {e.Message}"); + } + } + + public List SassyTextPatchers = new(); + public void RegisterPatcherToUniverse(SassyTextPatcher sassyTextPatcher) + { + SassyTextPatchers.Add(sassyTextPatcher); + } + + /// + /// This registers every patch in the files in the to register list + /// + public void RegisterAllPatches() + { + foreach (var (modId, patch) in _toRegister) + { + var gEnv = new GlobalEnvironment(this, modId); + var env = new Environment(gEnv); + patch.ExecuteIn(env); + } + + // Now we get to do the fun stuff with stages + foreach (var stage in UnsortedStages.Values) + stage.UpdateRequirements(UnsortedStages.Keys.ToList()); + SortStages(); + // Now lets update configs + foreach (var (_,label,name,updateExpression,environment) in ConfigUpdates) + { + var interpLabel = label.Interpolate(environment); + if (!Configs.TryGetValue(interpLabel, out var labelDict)) + labelDict = Configs[interpLabel] = new Dictionary(); + var subEnv = new Environment(environment.GlobalEnvironment,environment); + if (name != null) + { + var interpName = name.Interpolate(environment); + if (labelDict.TryGetValue(interpName, out var toAddValue)) + { + subEnv["value"] = toAddValue; + } + else + { + subEnv["value"] = labelDict[interpName] = new DataValue(DataValue.DataType.None); + } + + var result = updateExpression.Compute(subEnv); + if (result.IsDeletion) + { + labelDict.Remove(name); + } + else + { + labelDict[interpName] = result; + } + } + else + { + subEnv["value"] = DataValue.From(labelDict); + var result = updateExpression.Compute(subEnv); + if (result.IsDeletion) + { + labelDict.Clear(); + } + else if (!result.IsDictionary) + { + throw new InterpreterException(updateExpression.Coordinate, + "Updating a config label must result in a dictionary or deletion value."); + } + else + { + Configs[label] = result.Dictionary; + } + } + } + + foreach (var patcher in SassyTextPatchers) + { + var stage = patcher.PriorityString; + var modId = patcher.OriginalGuid; + if (AllStages.TryGetValue(stage, out var priority)) + { + patcher.Priority = priority; + } else if (AllStages.TryGetValue($"{modId}:{stage}", out priority)) + { + patcher.Priority = priority; + } else if (AllStages.TryGetValue(modId, out priority)) + { + patcher.Priority = priority; + } + + RegisterPatcher(patcher); + } + } + + private void SortStages() + { + MessageLogger($"Sorting {UnsortedStages.Count} stages"); + List sortedStages = new(); + Dictionary toSort = new(UnsortedStages); + while (toSort.Count > 0) + { + if (!SingleSortStep(toSort, sortedStages)) + { + throw new Exception( + $"Unable to sort stages to define patch order, the following stages cause a circular dependency: {string.Join(", ", toSort.Keys)}"); + } + } + + // For debug purposes + MessageLogger("Sorted stages!"); + ulong n = 0; + foreach (var stage in sortedStages) + { + MessageLogger($"{stage}: {n}"); + AllStages[stage] = n++; + } + } + + + private static bool SingleSortStep( + Dictionary toBeSorted, + List sortedStages + ) + { + var remove = ""; + var found = false; + foreach (var (name, stage) in toBeSorted) + { + if (!stage.RunsAfter.All(sortedStages.Contains) || toBeSorted.Values.Any(x => x.RunsBefore.Contains(name))) + { + continue; + } + + remove = name; + found = true; + sortedStages.Add(name); + break; + } + + if (found) + { + toBeSorted.Remove(remove); + } + return found; + } + + public void PatchLabels(params string[] labels) + { + LoadedLabels.AddRange(labels); + } + + public readonly Dictionary UnsortedStages = new(); + public readonly Dictionary LastImplicitWithinMod = new(); + public string LastImplicitGlobal = ""; + + private void SetupBasePriorities(List modLoadOrder) + { + MessageLogger($"Setting up base priorities with mod load order: {string.Join(", ", modLoadOrder)}"); + var lastPost = ""; + foreach (var mod in modLoadOrder) + { + var stage = new Stage(); + if (lastPost.Length > 0) + stage.RunsAfter.Add(lastPost); + UnsortedStages[mod] = stage; + MessageLogger($"Adding stage: {mod}"); + var post = new Stage(); + post.RunsAfter.Add(mod); + lastPost = $"{mod}:post"; + UnsortedStages[lastPost] = post; + MessageLogger($"Adding stage: {lastPost}"); + LastImplicitWithinMod[mod] = mod; + } + LastImplicitGlobal = lastPost; + MessageLogger($"Last implicit global: {lastPost}"); + } + + public static void RegisterRawLibrary(string modId, string name, string raw) + { + AllRawLibraries.Add($"{modId}:{name}", raw); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Execution/Universe.cs.meta b/Runtime/SassyPatching/Execution/Universe.cs.meta new file mode 100644 index 0000000..eec13b0 --- /dev/null +++ b/Runtime/SassyPatching/Execution/Universe.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 90742847863949b4cb016a947ac7bd6c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Interfaces.meta b/Runtime/SassyPatching/Interfaces.meta new file mode 100644 index 0000000..6ff4377 --- /dev/null +++ b/Runtime/SassyPatching/Interfaces.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4885d0910d92a8b4d8f78b9107c9b8df +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Interfaces/IModifiable.cs b/Runtime/SassyPatching/Interfaces/IModifiable.cs new file mode 100644 index 0000000..c0b70f6 --- /dev/null +++ b/Runtime/SassyPatching/Interfaces/IModifiable.cs @@ -0,0 +1,38 @@ +namespace PatchManager.SassyPatching.Interfaces +{ + /// + /// Represents a modifiable value + /// + public interface IModifiable + { + /// + /// Gets the value of a field + /// + /// The name of the field + /// The value of the field + public DataValue GetFieldValue(string fieldName); + /// + /// Sets the value of a field + /// + /// The name of the field + /// The value to set it to + public void SetFieldValue(string fieldName, DataValue dataValue); + + /// + /// Set this object to another value + /// + /// The value to set it to + public void Set(DataValue dataValue); + + /// + /// Get the value of this object + /// + /// The value of the object + public DataValue Get(); + + /// + /// Finalize modification of this object, and close its modification + /// + public void Complete(); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Interfaces/IModifiable.cs.meta b/Runtime/SassyPatching/Interfaces/IModifiable.cs.meta new file mode 100644 index 0000000..99b5193 --- /dev/null +++ b/Runtime/SassyPatching/Interfaces/IModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb469ea716176144ebe39295cb48f8e3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Interfaces/INewAsset.cs b/Runtime/SassyPatching/Interfaces/INewAsset.cs new file mode 100644 index 0000000..aeabf12 --- /dev/null +++ b/Runtime/SassyPatching/Interfaces/INewAsset.cs @@ -0,0 +1,14 @@ +namespace PatchManager.SassyPatching.Interfaces +{ + /// + /// Represents a new asset being created + /// + public interface INewAsset + { + public string Label { get; } + public string Name { get; } + public string Text { get; } + + public ISelectable Selectable { get; } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Interfaces/INewAsset.cs.meta b/Runtime/SassyPatching/Interfaces/INewAsset.cs.meta new file mode 100644 index 0000000..e459b99 --- /dev/null +++ b/Runtime/SassyPatching/Interfaces/INewAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 311834072fc3784449e9d8ffae4cc0e2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Interfaces/IPatcherRuleSet.cs b/Runtime/SassyPatching/Interfaces/IPatcherRuleSet.cs new file mode 100644 index 0000000..2d4dd54 --- /dev/null +++ b/Runtime/SassyPatching/Interfaces/IPatcherRuleSet.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; + +namespace PatchManager.SassyPatching.Interfaces +{ + // Essentially the ruleset requires ISelectable + /// + /// A ruleset for the patcher (the ":..." selectors) + /// + public interface IPatcherRuleSet + { + /// + /// What type of patch type will this ruleset match + /// + /// The label to match + /// True if the label matches the ruleset + public bool Matches(string label); + + /// + /// This converts json data to an ISelectable for the rest of the engine to use + /// + /// The type of data to convert to an ISelectale + /// The name of the data + /// The data to convert to an ISelectable + /// The selectable representing the data + public ISelectable ConvertToSelectable(string type, string name, string jsonData); + + + /// + /// Creates a new asset for the patcher + /// + /// The data values to create the asset from + /// The new asset + public INewAsset CreateNew(List dataValues); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Interfaces/IPatcherRuleSet.cs.meta b/Runtime/SassyPatching/Interfaces/IPatcherRuleSet.cs.meta new file mode 100644 index 0000000..76489a8 --- /dev/null +++ b/Runtime/SassyPatching/Interfaces/IPatcherRuleSet.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9e3f2cd1ed1fd6546be62dd7ad281953 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Interfaces/ISelectable.cs b/Runtime/SassyPatching/Interfaces/ISelectable.cs new file mode 100644 index 0000000..35e66dd --- /dev/null +++ b/Runtime/SassyPatching/Interfaces/ISelectable.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; + +namespace PatchManager.SassyPatching.Interfaces +{ + /// + /// Represents a selectable object + /// + public interface ISelectable + { + /// + /// Select all children + /// + /// All children + public List SelectEverything(); + + /// + /// Test if this selectable matches a name pattern + /// + /// The pattern being matched against + /// True if it matches the name pattern + public bool MatchesName(string name); + /// + /// Test if this selectable has a class + /// + /// The class + /// True if it has the class + public bool MatchesClass(string @class); + + /// + /// Get the value for a class + /// + public bool MatchesClass(string @class, out DataValue classValue); + + + /// + /// Test if this selectable is an element + /// + /// The element + /// True if it is the element + public bool MatchesElement(string element); + + /// + /// Checks if this selectable is the same as another selectable + /// + /// The selectable to be checked against + /// True if they are the same + public bool IsSameAs(ISelectable other); + + /// + /// Opens up this selectable for modification + /// + /// The modifiable state of this selector or null if not modifiable + public IModifiable OpenModification(); + + /// + /// Adds an element to this selectable and returns the selectable for it + /// + /// Thrown if this selectable cannot be modified + public ISelectable AddElement(string elementType); + + /// + /// Convert the ISelectable back to its string form, used to finalize a patch + /// + /// A string representing all the data contained in the ISelectable, usually in JSON + public string Serialize(); + + /// + /// Converts the selectable into a DataValue + /// + /// The value representation of the selectable + public DataValue GetValue(); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Interfaces/ISelectable.cs.meta b/Runtime/SassyPatching/Interfaces/ISelectable.cs.meta new file mode 100644 index 0000000..e6d4269 --- /dev/null +++ b/Runtime/SassyPatching/Interfaces/ISelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 938e941e2737b7949a2f886a334e28f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Modifiables.meta b/Runtime/SassyPatching/Modifiables.meta new file mode 100644 index 0000000..2177a79 --- /dev/null +++ b/Runtime/SassyPatching/Modifiables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0a107c26063bff24d91365294a0cc7d9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Modifiables/CustomJTokenModifiable.cs b/Runtime/SassyPatching/Modifiables/CustomJTokenModifiable.cs new file mode 100644 index 0000000..791f7b5 --- /dev/null +++ b/Runtime/SassyPatching/Modifiables/CustomJTokenModifiable.cs @@ -0,0 +1,109 @@ +using System; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching.Interfaces; +// ReSharper disable CognitiveComplexity + +namespace PatchManager.SassyPatching.Modifiables +{ + public abstract class CustomJTokenModifiable : IModifiable + { + /// + /// This is the data stored w/in this modifiable strucure + /// + protected readonly JToken JToken; + private readonly Action _setDirty; + + /// + /// Deletes a token, or if its a property, its parent + /// + /// + private static void RemoveToken(JToken token) + { + if (token.Parent is JProperty) + { + token.Parent.Remove(); + } + else + { + token.Remove(); + } + } + + /// + /// + /// + /// + /// + protected CustomJTokenModifiable(JToken jToken, Action setDirty) + { + JToken = jToken; + _setDirty = setDirty; + } + + /// + /// Sets a JToken to a value, taking care of deletions + /// + /// The JToken being set or replaced + /// The Value to replace it with + protected static void Set(JToken jToken, DataValue dataValue) + { + if (dataValue.IsDeletion) + { + RemoveToken(jToken); + } + else + { + jToken.Replace(dataValue.ToJToken()); + } + } + + /// + public virtual DataValue GetFieldValue(string fieldName) + { + try + { + return DataValue.FromJToken(JToken[fieldName]); + } + catch + { + return new DataValue(DataValue.DataType.None); + } + } + + /// + public virtual void SetFieldValue(string fieldName, DataValue dataValue) + { + _setDirty(); + if (dataValue.IsDeletion) + { + if (JToken is JObject obj && obj.ContainsKey(fieldName)) + JToken[fieldName]!.Remove(); + } + else + { + if (JToken is JObject obj && !obj.ContainsKey(fieldName)) + JToken[fieldName] = dataValue.ToJToken(); + else + JToken[fieldName]!.Replace(dataValue.ToJToken()); + } + } + + /// + public virtual void Set(DataValue dataValue) + { + _setDirty(); + Set(JToken, dataValue); + } + + /// + public virtual DataValue Get() + { + return DataValue.FromJToken(JToken); + } + + /// + public virtual void Complete() + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Modifiables/CustomJTokenModifiable.cs.meta b/Runtime/SassyPatching/Modifiables/CustomJTokenModifiable.cs.meta new file mode 100644 index 0000000..5859488 --- /dev/null +++ b/Runtime/SassyPatching/Modifiables/CustomJTokenModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a8920002a4beb946808f154189e0c2e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Modifiables/JTokenModifiable.cs b/Runtime/SassyPatching/Modifiables/JTokenModifiable.cs new file mode 100644 index 0000000..b9e5b1a --- /dev/null +++ b/Runtime/SassyPatching/Modifiables/JTokenModifiable.cs @@ -0,0 +1,88 @@ +using System; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching.Interfaces; + +namespace PatchManager.SassyPatching.Modifiables +{ + public class JTokenModifiable : IModifiable + { + private JToken _jToken; + private readonly Action _setDirty; + + private static void RemoveToken(JToken token) + { + if (token.Parent is JProperty) + { + token.Parent.Remove(); + } + else + { + token.Remove(); + } + } + + public JTokenModifiable(JToken jToken, Action setDirty) + { + _jToken = jToken; + this._setDirty = setDirty; + } + + public DataValue GetFieldValue(string fieldName) + { + try + { + return DataValue.FromJToken(_jToken[fieldName]); + } + catch + { + return DataValue.Null; + } + } + + public void SetFieldValue(string fieldName, DataValue dataValue) + { + _setDirty(); + if (dataValue.IsDeletion) + { + if (_jToken[fieldName].Parent is JProperty jProperty) + { + jProperty.Remove(); + } + else + { + _jToken[fieldName].Remove(); + } + } + else + { + if (_jToken is JObject obj && !obj.ContainsKey(fieldName)) + _jToken[fieldName] = dataValue.ToJToken(); + else + _jToken[fieldName].Replace(dataValue.ToJToken()); + } + } + + public virtual void Set(DataValue dataValue) + { + _setDirty(); + if (dataValue.IsDeletion) + { + // _jToken.Remove(); + RemoveToken(_jToken); + } + else + { + _jToken.Replace(dataValue.ToJToken()); + } + } + + public DataValue Get() + { + return DataValue.FromJToken(_jToken); + } + + public void Complete() + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Modifiables/JTokenModifiable.cs.meta b/Runtime/SassyPatching/Modifiables/JTokenModifiable.cs.meta new file mode 100644 index 0000000..c972235 --- /dev/null +++ b/Runtime/SassyPatching/Modifiables/JTokenModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 122c6844f56160643880b027ae4dd9cf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/NewAssets.meta b/Runtime/SassyPatching/NewAssets.meta new file mode 100644 index 0000000..c798531 --- /dev/null +++ b/Runtime/SassyPatching/NewAssets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 970158afdae97a947bceb5a7e331b531 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/NewAssets/NewGenericAsset.cs b/Runtime/SassyPatching/NewAssets/NewGenericAsset.cs new file mode 100644 index 0000000..030a0e9 --- /dev/null +++ b/Runtime/SassyPatching/NewAssets/NewGenericAsset.cs @@ -0,0 +1,35 @@ +using PatchManager.SassyPatching.Interfaces; + +namespace PatchManager.SassyPatching.NewAssets +{ + /// + /// Represents a newly made generic asset + /// + public class NewGenericAsset : INewAsset + { + /// + /// Create a descriptor for a new asset + /// + /// The label of the asset + /// The name of the asset + /// the selectable of the asset + public NewGenericAsset(string label, string name, ISelectable selectable) + { + Label = label; + Name = name; + Selectable = selectable; + } + + /// + public string Label { get; } + + /// + public string Name { get; } + + /// + public string Text => Selectable.Serialize(); + + /// + public ISelectable Selectable { get; } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/NewAssets/NewGenericAsset.cs.meta b/Runtime/SassyPatching/NewAssets/NewGenericAsset.cs.meta new file mode 100644 index 0000000..c643569 --- /dev/null +++ b/Runtime/SassyPatching/NewAssets/NewGenericAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 902d91408a1f661419b18da2551410ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes.meta b/Runtime/SassyPatching/Nodes.meta new file mode 100644 index 0000000..94caaff --- /dev/null +++ b/Runtime/SassyPatching/Nodes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3359c50ba98993e49bbd53bdab9a8d2f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Argument.cs b/Runtime/SassyPatching/Nodes/Argument.cs new file mode 100644 index 0000000..5205135 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Argument.cs @@ -0,0 +1,32 @@ +using JetBrains.Annotations; +using PatchManager.SassyPatching.Nodes.Expressions; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes +{ + /// + /// Represents an argument definition for a function/mixin + /// + public class Argument : Node + { + /// + /// The name of the argument being defined + /// + public readonly string Name; + /// + /// The default value of the argument if there is one + /// + public readonly Expression? Value; + + internal Argument(Coordinate c, string name, Expression? value = null) : base(c) + { + Name = name; + Value = value; + } + + /// + public override void ExecuteIn(Environment environment) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Argument.cs.meta b/Runtime/SassyPatching/Nodes/Argument.cs.meta new file mode 100644 index 0000000..b6cbcf8 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Argument.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 557aa8e506e94d44caecba96d5de5c27 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Attributes.meta b/Runtime/SassyPatching/Nodes/Attributes.meta new file mode 100644 index 0000000..e058ccc --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 044e87dfdf91ca541b2f5b9741eb14c2 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Attributes/NewAttribute.cs b/Runtime/SassyPatching/Nodes/Attributes/NewAttribute.cs new file mode 100644 index 0000000..3091dae --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/NewAttribute.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Nodes.Expressions; + +namespace PatchManager.SassyPatching.Nodes.Attributes +{ + public class NewAttribute : SelectorAttribute + { + public List Arguments; + public NewAttribute(Coordinate c, List arguments) : base(c) => Arguments = arguments; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Attributes/NewAttribute.cs.meta b/Runtime/SassyPatching/Nodes/Attributes/NewAttribute.cs.meta new file mode 100644 index 0000000..5982c98 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/NewAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 14cdd546423e0a54c8ea92edac89ae95 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions.meta b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions.meta new file mode 100644 index 0000000..331d166 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2984161cc67799845859a84ce6c72670 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireAnd.cs b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireAnd.cs new file mode 100644 index 0000000..c7a5aa2 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireAnd.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions +{ + public class RequireAnd : RequireExpression + { + public RequireExpression LeftHandSide; + public RequireExpression RightHandSide; + + public RequireAnd(Coordinate c, RequireExpression lhs, RequireExpression rhs) : base(c) + { + LeftHandSide = lhs; + RightHandSide = rhs; + } + + public override bool Execute(IReadOnlyCollection loadedMods, Environment e) => + LeftHandSide.Execute(loadedMods, e) && RightHandSide.Execute(loadedMods, e); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireAnd.cs.meta b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireAnd.cs.meta new file mode 100644 index 0000000..28aa6be --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireAnd.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0851caabfcfd81949aaa78e41edc5ed7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireExpression.cs b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireExpression.cs new file mode 100644 index 0000000..1f7c0a5 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireExpression.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions +{ + /// + /// Represents a node in a require expression + /// + public abstract class RequireExpression : Node + { + internal RequireExpression(Coordinate c) : base(c) { } + + /// + public override void ExecuteIn(Environment environment) { } + + public abstract bool Execute(IReadOnlyCollection loadedMods, Environment e); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireExpression.cs.meta b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireExpression.cs.meta new file mode 100644 index 0000000..a158b76 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireExpression.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2a1645d5a14ad8640be901ee13bdc6ee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireGuid.cs b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireGuid.cs new file mode 100644 index 0000000..6560d2d --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireGuid.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Utility; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions +{ + public class RequireGuid : RequireExpression + { + public string Guid; + + public RequireGuid(Coordinate c, string guid) : base(c) => Guid = guid; + + public override bool Execute(IReadOnlyCollection loadedMods, Environment e) => loadedMods.Contains(Guid.Interpolate(e)); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireGuid.cs.meta b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireGuid.cs.meta new file mode 100644 index 0000000..922fed8 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireGuid.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 76efa55a354119c4db89fb6631aaf89b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireNot.cs b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireNot.cs new file mode 100644 index 0000000..d9a1b76 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireNot.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions +{ + public class RequireNot : RequireExpression + { + public RequireExpression Child; + + public RequireNot(Coordinate c, RequireExpression child) : base(c) => Child = child; + public override bool Execute(IReadOnlyCollection loadedMods, Environment e) => !Child.Execute(loadedMods, e); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireNot.cs.meta b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireNot.cs.meta new file mode 100644 index 0000000..1afe8cd --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireNot.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36e41536ac6731a40aa99a7f347f4d8b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireOr.cs b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireOr.cs new file mode 100644 index 0000000..6a8c204 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireOr.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions +{ + public class RequireOr : RequireExpression + { + public RequireExpression LeftHandSide; + public RequireExpression RightHandSide; + + public RequireOr(Coordinate c, RequireExpression lhs, RequireExpression rhs) : base(c) + { + LeftHandSide = lhs; + RightHandSide = rhs; + } + + public override bool Execute(IReadOnlyCollection loadedMods, Environment e) => + LeftHandSide.Execute(loadedMods, e) || RightHandSide.Execute(loadedMods, e); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireOr.cs.meta b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireOr.cs.meta new file mode 100644 index 0000000..e0a0c27 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireExpressions/RequireOr.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3eee758a50132c5408b6bed000c87866 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireModAttribute.cs b/Runtime/SassyPatching/Nodes/Attributes/RequireModAttribute.cs new file mode 100644 index 0000000..f09389a --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireModAttribute.cs @@ -0,0 +1,14 @@ +using PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions; + +namespace PatchManager.SassyPatching.Nodes.Attributes +{ + /// + /// Represents an attribute that modifies a selection block to only run if a mod is loaded + /// + public class RequireModAttribute : SelectorAttribute + { + public readonly RequireExpression Expression; + + internal RequireModAttribute(Coordinate c, RequireExpression expression) : base(c) => Expression = expression; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Attributes/RequireModAttribute.cs.meta b/Runtime/SassyPatching/Nodes/Attributes/RequireModAttribute.cs.meta new file mode 100644 index 0000000..769e3ad --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RequireModAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 38d576999dd17f648b77bb366bce5e87 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Attributes/RunAtStageAttribute.cs b/Runtime/SassyPatching/Nodes/Attributes/RunAtStageAttribute.cs new file mode 100644 index 0000000..f29ee1f --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RunAtStageAttribute.cs @@ -0,0 +1,18 @@ +namespace PatchManager.SassyPatching.Nodes.Attributes +{ + /// + /// Represents an attribute that defines the stage of a selection block + /// This should only be on top level blocks + /// + public class RunAtStageAttribute : SelectorAttribute + { + /// + /// The stage that the attributed selection block will run at + /// + public readonly string Stage; + internal RunAtStageAttribute(Coordinate c, string stage) : base(c) + { + Stage = stage; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Attributes/RunAtStageAttribute.cs.meta b/Runtime/SassyPatching/Nodes/Attributes/RunAtStageAttribute.cs.meta new file mode 100644 index 0000000..0ecbfcc --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/RunAtStageAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: be07b1af50322ed46870b80cea870342 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Attributes/SelectorAttribute.cs b/Runtime/SassyPatching/Nodes/Attributes/SelectorAttribute.cs new file mode 100644 index 0000000..682ad3a --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/SelectorAttribute.cs @@ -0,0 +1,19 @@ +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Attributes +{ + /// + /// Represents an attribute applied to a selection block + /// + public abstract class SelectorAttribute : Node + { + internal SelectorAttribute(Coordinate c) : base(c) + { + } + + /// + public override void ExecuteIn(Environment environment) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Attributes/SelectorAttribute.cs.meta b/Runtime/SassyPatching/Nodes/Attributes/SelectorAttribute.cs.meta new file mode 100644 index 0000000..05c8ebf --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Attributes/SelectorAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f15b9da13654e814491a353157ec740f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Block.cs b/Runtime/SassyPatching/Nodes/Block.cs new file mode 100644 index 0000000..faea572 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Block.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes +{ + /// + /// Represents a group of nodes + /// + public class Block : Node, ISelectionAction + { + /// + /// The children of this block node + /// + public readonly List Children; + + internal Block(Coordinate c, List children) : base(c) + { + Children = children; + } + + /// + public override void ExecuteIn(Environment environment) + { + foreach (var child in Children) + { + child.ExecuteIn(environment); + } + } + + /// + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) + { + foreach (var child in Children) + { + if (child is ISelectionAction selectionAction) + { + selectionAction.ExecuteOn(environment,selectable,modifiable); + } + else + { + child.ExecuteIn(environment); + } + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Block.cs.meta b/Runtime/SassyPatching/Nodes/Block.cs.meta new file mode 100644 index 0000000..ebfa2a3 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Block.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 115a5902bd201544ebb9cebb8d9bdd8e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/CallArgument.cs b/Runtime/SassyPatching/Nodes/CallArgument.cs new file mode 100644 index 0000000..e5252e8 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/CallArgument.cs @@ -0,0 +1,54 @@ +using JetBrains.Annotations; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Nodes.Expressions; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes +{ + /// + /// Represents an argument in a function call + /// + public class CallArgument : Node + { + /// + /// The name of the argument, if it is a named argument + /// + public readonly string? ArgumentName; + /// + /// The value passed to the function/mixin being called/instantiated + /// + public readonly Expression ArgumentValue; + + /// + /// Creates a named call argument + /// + /// The location of the argument + /// The name of the argument + /// The value being passed + public CallArgument(Coordinate c, string? argumentName, Expression argumentValue) : base(c) + { + ArgumentName = argumentName; + ArgumentValue = argumentValue; + } + + internal CallArgument(Coordinate c, Expression argumentValue) : base(c) + { + ArgumentName = null; + ArgumentValue = argumentValue; + } + + /// + public override void ExecuteIn(Environment environment) + { + } + + public PatchArgument Compute(Environment environment) + { + return new PatchArgument + { + ArgumentName = ArgumentName, + ArgumentDataValue = ArgumentValue.Compute(environment) + }; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/CallArgument.cs.meta b/Runtime/SassyPatching/Nodes/CallArgument.cs.meta new file mode 100644 index 0000000..ea3850d --- /dev/null +++ b/Runtime/SassyPatching/Nodes/CallArgument.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f159d93a50a89f145b5844fb67dd9c53 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/ErrorNode.cs b/Runtime/SassyPatching/Nodes/ErrorNode.cs new file mode 100644 index 0000000..6aab672 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/ErrorNode.cs @@ -0,0 +1,26 @@ +using PatchManager.SassyPatching.Exceptions; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes +{ + /// + /// A node representing a transformation error + /// + public class ErrorNode : Node + { + /// + /// The error message + /// + public string Error; + internal ErrorNode(Coordinate c, string error) : base(c) + { + Error = error; + } + + /// + public override void ExecuteIn(Environment environment) + { + throw new InterpreterException(Coordinate, Error); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/ErrorNode.cs.meta b/Runtime/SassyPatching/Nodes/ErrorNode.cs.meta new file mode 100644 index 0000000..6f172e8 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/ErrorNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b259647eb60d99340a1d470865853e45 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions.meta b/Runtime/SassyPatching/Nodes/Expressions.meta new file mode 100644 index 0000000..3aa4466 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5cdc3f32efe309e4c871e6fcfb78e74e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary.meta new file mode 100644 index 0000000..20b8224 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d5de348c519108d44815d819e09c13b5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Add.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/Add.cs new file mode 100644 index 0000000..c9d3473 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Add.cs @@ -0,0 +1,30 @@ +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression which adds its 2 children together and returns the result + /// + public class Add : Binary + { + internal Add(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide + rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate, "add", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + + internal override bool ShortCircuitOn(DataValue dataValue) => false; + internal override DataValue ShortCircuitDataValue => null; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Add.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/Add.cs.meta new file mode 100644 index 0000000..f631b96 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Add.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5332357b18e8c71439fc0281ee46fc52 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/And.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/And.cs new file mode 100644 index 0000000..458c72f --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/And.cs @@ -0,0 +1,19 @@ +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression that returns true if both children are truthy (short circuits) + /// + /// + public class And : Binary + { + public And(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) => rightHandSide.Truthy; + + internal override bool ShortCircuitOn(DataValue dataValue) => !dataValue.Truthy; + + internal override DataValue ShortCircuitDataValue => false; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/And.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/And.cs.meta new file mode 100644 index 0000000..d01cae5 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/And.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 423d476a73679c04b8687e5981d6b0ab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Binary.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/Binary.cs new file mode 100644 index 0000000..0757477 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Binary.cs @@ -0,0 +1,44 @@ +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expressions which performs a computation on 2 values to return one value + /// + public abstract class Binary : Expression + { + /// + /// The left hand side of this expression + /// + public readonly Expression LeftHandSide; + /// + /// The right hand side of this expression + /// + public readonly Expression RightHandSide; + + internal Binary(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c) + { + LeftHandSide = leftHandSide; + RightHandSide = rightHandSide; + } + + internal abstract DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide); + + internal abstract bool ShortCircuitOn(DataValue dataValue); + + internal abstract DataValue ShortCircuitDataValue { get; } + + /// + public override DataValue Compute(Environment environment) + { + var lhs = LeftHandSide.Compute(environment); + if (ShortCircuitOn(lhs)) + { + return ShortCircuitDataValue; + } + + var rhs = RightHandSide.Compute(environment); + return GetResult(lhs, rhs); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Binary.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/Binary.cs.meta new file mode 100644 index 0000000..6beeae0 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Binary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e2fe32a80e6a5544fbb45d657f831b7a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Divide.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/Divide.cs new file mode 100644 index 0000000..c323e1a --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Divide.cs @@ -0,0 +1,30 @@ +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression which divides the left hand side by the right hand side + /// + public class Divide : Binary + { + internal Divide(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide / rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate, "divide", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + + internal override bool ShortCircuitOn(DataValue dataValue) => false; + internal override DataValue ShortCircuitDataValue => null; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Divide.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/Divide.cs.meta new file mode 100644 index 0000000..611e20b --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Divide.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 86ad6edfc52bf094099cc9777d4e75f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/EqualTo.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/EqualTo.cs new file mode 100644 index 0000000..4c74f04 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/EqualTo.cs @@ -0,0 +1,19 @@ +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression that returns true if both of its children are equal + /// + public class EqualTo : Binary + { + internal EqualTo(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) => + leftHandSide == rightHandSide; + + internal override bool ShortCircuitOn(DataValue dataValue) => false; + + internal override DataValue ShortCircuitDataValue => null; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/EqualTo.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/EqualTo.cs.meta new file mode 100644 index 0000000..a0eda7a --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/EqualTo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d2dcf2917172fef468449eca33d31aab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThan.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThan.cs new file mode 100644 index 0000000..203f536 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThan.cs @@ -0,0 +1,31 @@ +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression that returns true if its left hand side is greater than its right hand side + /// + public class GreaterThan : Binary + { + internal GreaterThan(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide > rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate,"perform a relational comparison (>)", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + + internal override bool ShortCircuitOn(DataValue dataValue) => false; + + internal override DataValue ShortCircuitDataValue => null; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThan.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThan.cs.meta new file mode 100644 index 0000000..5119caa --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThan.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7834b2326d2c7dc4bb9f02320cef712b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThanEqual.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThanEqual.cs new file mode 100644 index 0000000..9b901ac --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThanEqual.cs @@ -0,0 +1,31 @@ +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression that returns true if its left hand side is greater than or equal to its right hand side + /// + public class GreaterThanEqual : Binary + { + internal GreaterThanEqual(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide >= rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate,"perform a relational comparison (>=)", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + + internal override bool ShortCircuitOn(DataValue dataValue) => false; + + internal override DataValue ShortCircuitDataValue => null; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThanEqual.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThanEqual.cs.meta new file mode 100644 index 0000000..7c6c0aa --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/GreaterThanEqual.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 98f715936d936ae418b18be0018daef1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThan.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThan.cs new file mode 100644 index 0000000..a0c191b --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThan.cs @@ -0,0 +1,32 @@ +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression that returns true if its left hand side is less than its right hand side + /// + public class LesserThan : Binary + { + internal LesserThan(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + + try + { + return leftHandSide < rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate,"perform a relational comparison (<)", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + + internal override bool ShortCircuitOn(DataValue dataValue) => false; + + internal override DataValue ShortCircuitDataValue => null; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThan.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThan.cs.meta new file mode 100644 index 0000000..5278291 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThan.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7204921ba4814444fa9b85e93e6cc989 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThanEqual.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThanEqual.cs new file mode 100644 index 0000000..01fddc9 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThanEqual.cs @@ -0,0 +1,30 @@ +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression that returns true if its left hand side is less than or equal to its right hand side + /// + public class LesserThanEqual : Binary + { + internal LesserThanEqual(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide <= rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate,"perform a relational comparison (<=)", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + + internal override bool ShortCircuitOn(DataValue dataValue) => false; + internal override DataValue ShortCircuitDataValue => null; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThanEqual.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThanEqual.cs.meta new file mode 100644 index 0000000..e6597ba --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/LesserThanEqual.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e2404407e58d624589bae45ad8f68d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Multiply.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/Multiply.cs new file mode 100644 index 0000000..accb668 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Multiply.cs @@ -0,0 +1,34 @@ +using System.Text; +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression which multiplies its 2 children together and returns the result + /// + public class Multiply : Binary + { + internal Multiply(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide * rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate, "multiply", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + + + + internal override bool ShortCircuitOn(DataValue dataValue) => false; + + internal override DataValue ShortCircuitDataValue => null; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Multiply.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/Multiply.cs.meta new file mode 100644 index 0000000..0afbb1f --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Multiply.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fb7d5b57461d2164c87bb14d05230bdb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/NotEqualTo.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/NotEqualTo.cs new file mode 100644 index 0000000..6596150 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/NotEqualTo.cs @@ -0,0 +1,19 @@ +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression that returns true if both of its children are not equal + /// + public class NotEqualTo : Binary + { + internal NotEqualTo(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) => + leftHandSide != rightHandSide; + + internal override bool ShortCircuitOn(DataValue dataValue) => false; + + internal override DataValue ShortCircuitDataValue => null; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/NotEqualTo.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/NotEqualTo.cs.meta new file mode 100644 index 0000000..4ed37b8 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/NotEqualTo.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 9377e9340b8362d4b9b9711a794a4ca9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Or.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/Or.cs new file mode 100644 index 0000000..e49d3df --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Or.cs @@ -0,0 +1,20 @@ +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression that returns true if either child is truthy (short circuits) + /// + /// + public class Or : Binary + { + internal Or(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + // This should only be called if the left hand side is falsy + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) => rightHandSide.Truthy; + + internal override bool ShortCircuitOn(DataValue dataValue) => dataValue.Truthy; + + internal override DataValue ShortCircuitDataValue => true; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Or.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/Or.cs.meta new file mode 100644 index 0000000..c66166a --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Or.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 35e38b0905c477d4c8eae0b69a21cd7c +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Remainder.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/Remainder.cs new file mode 100644 index 0000000..e762cde --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Remainder.cs @@ -0,0 +1,31 @@ +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression which divides the left hand side by the right hand side and returns the remainder + /// + public class Remainder : Binary + { + internal Remainder(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide % rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate, "take the remainder of", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + + internal override bool ShortCircuitOn(DataValue dataValue) => false; + + internal override DataValue ShortCircuitDataValue => null; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Remainder.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/Remainder.cs.meta new file mode 100644 index 0000000..a6261ac --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Remainder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 16847ac49966c9a4f9584b4b4d237345 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Subscript.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/Subscript.cs new file mode 100644 index 0000000..3f637c8 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Subscript.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// A binary expression which indexes the left hand side by the right hand side and returns the result + /// + public class Subscript : Binary + { + internal Subscript(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + // ReSharper disable once CognitiveComplexity + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide[rightHandSide]; + } + catch (IndexOutOfRangeException indexOutOfRangeException) + { + throw new ListIndexOutOfRangeException(Coordinate, indexOutOfRangeException.Message); + } + catch (KeyNotFoundException keyNotFoundException) + { + throw new DictionaryKeyNotFoundException(Coordinate, keyNotFoundException.Message); + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate, "subscript", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + + internal override bool ShortCircuitOn(DataValue dataValue) => false; + + internal override DataValue ShortCircuitDataValue => null; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Subscript.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/Subscript.cs.meta new file mode 100644 index 0000000..fef1714 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Subscript.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e38e6c1ee05372a4fb79cf4a200e6e3b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Subtract.cs b/Runtime/SassyPatching/Nodes/Expressions/Binary/Subtract.cs new file mode 100644 index 0000000..ac87171 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Subtract.cs @@ -0,0 +1,31 @@ +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Binary +{ + /// + /// Represents a binary expression which subtracts the right hand side from the left hand side + /// + public class Subtract : Binary + { + internal Subtract(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide - rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate, "subtract", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + + internal override bool ShortCircuitOn(DataValue dataValue) => false; + + internal override DataValue ShortCircuitDataValue => null; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Binary/Subtract.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Binary/Subtract.cs.meta new file mode 100644 index 0000000..09f169f --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Binary/Subtract.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: af0360ca39df96249a058438bf3c2739 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Closure.cs b/Runtime/SassyPatching/Nodes/Expressions/Closure.cs new file mode 100644 index 0000000..7a46c7e --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Closure.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions +{ + /// + /// Represents a function definition + /// + public class Closure : Expression + { + /// + /// The list of arguments the function takes + /// + public readonly List Arguments; + /// + /// The list of statements to be executed upon a function call + /// + public readonly List Body; + internal Closure(Coordinate c, List arguments, List body) : base(c) + { + Arguments = arguments; + Body = body; + } + + /// + public override DataValue Compute(Environment environment) + { + return new SassyPatchClosure(environment.Snapshot(), this); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Closure.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Closure.cs.meta new file mode 100644 index 0000000..8ee8940 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Closure.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1634fe7d8ab853f4c8b9aa6ffffd5b43 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Expression.cs b/Runtime/SassyPatching/Nodes/Expressions/Expression.cs new file mode 100644 index 0000000..e71db8b --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Expression.cs @@ -0,0 +1,28 @@ +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions +{ + /// + /// Represents an expression node + /// + public abstract class Expression : Node + { + + /// + /// Computes the value of the expression in the given environment + /// + /// The environment to compute the expression within + /// The computed value + /// Thrown if any error happens + public abstract DataValue Compute(Environment environment); + internal Expression(Coordinate c) : base(c) + { + } + + /// + public override void ExecuteIn(Environment environment) + { + _ = Compute(environment); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Expression.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Expression.cs.meta new file mode 100644 index 0000000..e96266f --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Expression.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 08532dd1b4bcbfc43857f3cb9a44a6b5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/ListNode.cs b/Runtime/SassyPatching/Nodes/Expressions/ListNode.cs new file mode 100644 index 0000000..a979233 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/ListNode.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions +{ + /// + /// Represents a list initializer + /// + public class ListNode : Expression + { + /// + /// The list of values contained within this list + /// + public readonly List Expressions; + internal ListNode(Coordinate c, List expressions) : base(c) + { + Expressions = expressions; + } + + /// + public override DataValue Compute(Environment environment) + { + return Expressions.Select(x => x.Compute(environment)).ToList(); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/ListNode.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/ListNode.cs.meta new file mode 100644 index 0000000..f410878 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/ListNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c20d8f337ad69e043ad95e417e3aaa99 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/LocalVariableReference.cs b/Runtime/SassyPatching/Nodes/Expressions/LocalVariableReference.cs new file mode 100644 index 0000000..b10f866 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/LocalVariableReference.cs @@ -0,0 +1,26 @@ +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions +{ + /// + /// Represents a local variable (indexing into $current) + /// + public class LocalVariableReference : Expression + { + /// + /// The local variable $current[...] + /// + public readonly string LocalVariableName; + internal LocalVariableReference(Coordinate c, string localVariableName) : base(c) + { + LocalVariableName = localVariableName; + } + + /// + public override DataValue Compute(Environment environment) + { + var current = environment["current"].Dictionary; + return current.TryGetValue(LocalVariableName, out var compute) ? compute : new DataValue(DataValue.DataType.None); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/LocalVariableReference.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/LocalVariableReference.cs.meta new file mode 100644 index 0000000..45d484a --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/LocalVariableReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e20040d663d9eff478dfa085bfc44ac5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/MemberCall.cs b/Runtime/SassyPatching/Nodes/Expressions/MemberCall.cs new file mode 100644 index 0000000..c7374fd --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/MemberCall.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Execution; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions +{ + /// + /// Represents a member call, or a call syntax where the left hand side is the first argument + /// + public class MemberCall : Expression + { + /// + /// The object getting member called + /// + public readonly Expression LeftHandSide; + /// + /// The function being called, first tries to find a function named [LeftHandSide Type].name then name + /// + public readonly string FunctionName; + /// + /// The arguments being passed to the function, other than the left hand side + /// + public readonly List Arguments; + + internal MemberCall(Coordinate c, Expression leftHandSide, string functionName, List arguments) : base(c) + { + LeftHandSide = leftHandSide; + FunctionName = functionName; + Arguments = arguments; + } + + /// + public override DataValue Compute(Environment environment) + { + var lhs = LeftHandSide.Compute(environment); + var lhsType = lhs.Type.ToString().ToLowerInvariant(); + var args = new List + { + new PatchArgument + { + ArgumentName = null, + ArgumentDataValue = lhs + } + }; + args.AddRange(Arguments.Select(x => x.Compute(environment))); + if (environment.GlobalEnvironment.AllFunctions.TryGetValue($"{lhsType}.{FunctionName}", out var overloadedFunction)) + { + try + { + return overloadedFunction.Execute(environment,args); + } + catch (InterpreterException i) + { + throw; + } + catch (Exception e) + { + throw new InterpreterException(Coordinate, e.ToString()); + } + } + if (environment.GlobalEnvironment.AllFunctions.TryGetValue(FunctionName, out var function)) + { + try + { + return function.Execute(environment,args); + } + catch (InterpreterException i) + { + throw; + } + catch (Exception e) + { + throw new InterpreterException(Coordinate, e.ToString()); + } + } + + throw new InterpreterException(Coordinate, $"Attempting to call {FunctionName}/{lhsType}.{FunctionName} which does not exist"); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/MemberCall.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/MemberCall.cs.meta new file mode 100644 index 0000000..f2808b3 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/MemberCall.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 56e0687586b440f45aadad88763ba379 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/ObjectNode.cs b/Runtime/SassyPatching/Nodes/Expressions/ObjectNode.cs new file mode 100644 index 0000000..e601e4e --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/ObjectNode.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions +{ + /// + /// Represents an object initializer + /// + public class ObjectNode : Expression + { + /// + /// The fields being initialized in this object + /// + public readonly List Initializers; + internal ObjectNode(Coordinate c, List initializers) : base(c) + { + Initializers = initializers; + } + + /// + public override DataValue Compute(Environment environment) + { + return Initializers.ToDictionary(x => x.Key, x => x.Value.Compute(environment)); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/ObjectNode.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/ObjectNode.cs.meta new file mode 100644 index 0000000..ba20272 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/ObjectNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b3db26ba3fdb1743aafbedc05fcabeb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/SimpleCall.cs b/Runtime/SassyPatching/Nodes/Expressions/SimpleCall.cs new file mode 100644 index 0000000..fbfd9f2 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/SimpleCall.cs @@ -0,0 +1,51 @@ +using System; +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions +{ + /// + /// Represents a simple function call + /// + public class SimpleCall : Expression + { + /// + /// The function being called + /// + public readonly string FunctionName; + /// + /// The arguments being passed to the function call + /// + public readonly List Arguments; + + internal SimpleCall(Coordinate c, string functionName, List arguments) : base(c) + { + FunctionName = functionName; + Arguments = arguments; + } + + /// + public override DataValue Compute(Environment environment) + { + if (environment.GlobalEnvironment.AllFunctions.TryGetValue(FunctionName, out var function)) + { + try + { + return function.Execute(environment, Arguments.Select(x => x.Compute(environment)).ToList()); + } + catch (InterpreterException i) + { + throw; + } + catch (Exception e) + { + throw new InterpreterException(Coordinate, e.ToString()); + } + } + + throw new InterpreterException(Coordinate, $"Attempting to call {FunctionName} which does not exist"); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/SimpleCall.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/SimpleCall.cs.meta new file mode 100644 index 0000000..67d3144 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/SimpleCall.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b7ce0b53c99048b48b6f9108d29dd82d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Ternary.cs b/Runtime/SassyPatching/Nodes/Expressions/Ternary.cs new file mode 100644 index 0000000..72fd0bf --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Ternary.cs @@ -0,0 +1,35 @@ +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions +{ + /// + /// Represents a ternary expression, which computes the left hand side if the condition is true otherwise the righthand side + /// + public class Ternary : Expression + { + /// + /// The expression to be computed if the condition is true + /// + public readonly Expression LeftHandSide; + /// + /// The condition to be tested + /// + public readonly Expression Condition; + /// + /// The expression to be computed if the condition is false + /// + public readonly Expression RightHandSide; + + internal Ternary(Coordinate c, Expression leftHandSide, Expression condition, Expression rightHandSide) : base(c) + { + LeftHandSide = leftHandSide; + Condition = condition; + RightHandSide = rightHandSide; + } + + /// + public override DataValue Compute(Environment environment) => Condition.Compute(environment).Truthy + ? LeftHandSide.Compute(environment) + : RightHandSide.Compute(environment); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Ternary.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Ternary.cs.meta new file mode 100644 index 0000000..45fc7cd --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Ternary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c6d32720a2ab4e843af77da143801e9d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary.meta b/Runtime/SassyPatching/Nodes/Expressions/Unary.meta new file mode 100644 index 0000000..59cb8ae --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: abc5a919201dd4f4c95a0a23c6db9151 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/Implicit.cs b/Runtime/SassyPatching/Nodes/Expressions/Unary/Implicit.cs new file mode 100644 index 0000000..2cb599f --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/Implicit.cs @@ -0,0 +1,29 @@ +using System; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Unary +{ + /// + /// + /// Represents an implicit operation node, which is a node that grabs the variable $value from the environment and applies a computation to it + /// + /// + /// $value is always the value of the variable/field being modified + /// + /// + public abstract class Implicit : Unary + { + internal Implicit(Coordinate c, Expression child) : base(c, child) + { + } + internal abstract DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide); + + internal override DataValue GetResult(DataValue child) + { + throw new Exception("Unreachable"); + } + + /// + public override DataValue Compute(Environment environment) => GetResult(environment["value"], Child.Compute(environment)); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/Implicit.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Unary/Implicit.cs.meta new file mode 100644 index 0000000..ccda2b6 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/Implicit.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 63e73cda34cd1fd4ab5cb2a19be82aa4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitAdd.cs b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitAdd.cs new file mode 100644 index 0000000..505a8f4 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitAdd.cs @@ -0,0 +1,29 @@ +using System; +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Unary +{ + /// + /// Represents an implicit addition, which adds the child to $value + /// + public class ImplicitAdd : Implicit + { + internal ImplicitAdd(Coordinate c, Expression child) : base(c, child) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide + rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate, "add", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitAdd.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitAdd.cs.meta new file mode 100644 index 0000000..1acf5dd --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitAdd.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6098d600be34d604c92547e1a099a33b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitDivide.cs b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitDivide.cs new file mode 100644 index 0000000..fed87f1 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitDivide.cs @@ -0,0 +1,27 @@ +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Unary +{ + /// + /// Represent an implicit division which divides $value by its child + /// + public class ImplicitDivide : Implicit + { + internal ImplicitDivide(Coordinate c, Expression child) : base(c, child) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide / rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate, "divide", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitDivide.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitDivide.cs.meta new file mode 100644 index 0000000..38a7240 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitDivide.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3a3cb49311ad14f48a3fee5745f066be +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitMultiply.cs b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitMultiply.cs new file mode 100644 index 0000000..ae93c2b --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitMultiply.cs @@ -0,0 +1,28 @@ +using System.Text; +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Unary +{ + /// + /// Represents an implicit multiplication which multiplies $value by its child + /// + public class ImplicitMultiply : Implicit + { + internal ImplicitMultiply(Coordinate c, Expression child) : base(c, child) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide * rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate, "multiply", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitMultiply.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitMultiply.cs.meta new file mode 100644 index 0000000..b0c5142 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitMultiply.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 76ea1f99a2d84924d9b4f2a53b2fa3c7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitSubtract.cs b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitSubtract.cs new file mode 100644 index 0000000..bbbcfbd --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitSubtract.cs @@ -0,0 +1,27 @@ +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Unary +{ + /// + /// Represents an implicit subtraction which subtracts its child from $value + /// + public class ImplicitSubtract : Implicit + { + internal ImplicitSubtract(Coordinate c, Expression child) : base(c, child) + { + } + + internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) + { + try + { + return leftHandSide - rightHandSide; + } + catch (DataValueOperationException) + { + throw new BinaryExpressionTypeException(Coordinate, "subtract", leftHandSide.Type.ToString(), + rightHandSide.Type.ToString()); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitSubtract.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitSubtract.cs.meta new file mode 100644 index 0000000..772c691 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/ImplicitSubtract.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 847bf749d9d3e644ba917461e3fc29c6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/Negate.cs b/Runtime/SassyPatching/Nodes/Expressions/Unary/Negate.cs new file mode 100644 index 0000000..98eed73 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/Negate.cs @@ -0,0 +1,26 @@ +using PatchManager.SassyPatching.Exceptions; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Unary +{ + /// + /// Represents a negation operation which returns the negative value of its child + /// + public class Negate : Unary + { + internal Negate(Coordinate c, Expression child) : base(c, child) + { + } + + internal override DataValue GetResult(DataValue child) + { + try + { + return -child; + } + catch (DataValueOperationException) + { + throw new UnaryTypeException(Coordinate, "negate", child.Type.ToString()); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/Negate.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Unary/Negate.cs.meta new file mode 100644 index 0000000..c5eb118 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/Negate.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 619fb801bfaa47e4d85cfbdbea2dbdbb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/Not.cs b/Runtime/SassyPatching/Nodes/Expressions/Unary/Not.cs new file mode 100644 index 0000000..069400e --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/Not.cs @@ -0,0 +1,15 @@ +namespace PatchManager.SassyPatching.Nodes.Expressions.Unary +{ + /// + /// Represents a not operation which returns the opposite of the truthiness of its child + /// + /// + public class Not : Unary + { + internal Not(Coordinate c, Expression child) : base(c, child) + { + } + + internal override DataValue GetResult(DataValue child) => !child; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/Not.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Unary/Not.cs.meta new file mode 100644 index 0000000..47b0ab4 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/Not.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 65128c4f6790762498dab8bb153881f6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/Positive.cs b/Runtime/SassyPatching/Nodes/Expressions/Unary/Positive.cs new file mode 100644 index 0000000..6e5f5a1 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/Positive.cs @@ -0,0 +1,14 @@ +namespace PatchManager.SassyPatching.Nodes.Expressions.Unary +{ + /// + /// Represents a positive expression which returns its child + /// + public class Positive : Unary + { + internal Positive(Coordinate c, Expression child) : base(c, child) + { + } + + internal override DataValue GetResult(DataValue child) => +child; + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/Positive.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Unary/Positive.cs.meta new file mode 100644 index 0000000..f6d63e7 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/Positive.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 79bf0fbdb3e3c404fbcb763f84b671d4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/Unary.cs b/Runtime/SassyPatching/Nodes/Expressions/Unary/Unary.cs new file mode 100644 index 0000000..8978bc6 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/Unary.cs @@ -0,0 +1,30 @@ +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions.Unary +{ + /// + /// Represents a unary expression (an expression with one child) + /// + public abstract class Unary : Expression + { + /// + /// The child of this expression + /// + public readonly Expression Child; + + + + internal Unary(Coordinate c, Expression child) : base(c) + { + Child = child; + } + + internal abstract DataValue GetResult(DataValue child); + + /// + public override DataValue Compute(Environment environment) + { + return GetResult(Child.Compute(environment)); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/Unary/Unary.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/Unary/Unary.cs.meta new file mode 100644 index 0000000..b80bd75 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/Unary/Unary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: cd5c1271fe709b74f9912baa56bc351e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/ValueNode.cs b/Runtime/SassyPatching/Nodes/Expressions/ValueNode.cs new file mode 100644 index 0000000..d6d20b9 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/ValueNode.cs @@ -0,0 +1,40 @@ +using System; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Utility; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions +{ + /// + /// Represents a literal value + /// + public class ValueNode : Expression + { + /// + /// The literal value + /// + public readonly DataValue StoredDataValue; + internal ValueNode(Coordinate c, DataValue storedDataValue) : base(c) + { + StoredDataValue = storedDataValue; + } + + /// + public override DataValue Compute(Environment environment) + { + if (!StoredDataValue.IsString) + { + return StoredDataValue; + } + + try + { + return StoredDataValue.String.Interpolate(environment); + } + catch (Exception e) + { + throw new InterpolationException(Coordinate, e.Message); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/ValueNode.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/ValueNode.cs.meta new file mode 100644 index 0000000..ad54d5e --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/ValueNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 927067340df3bee479525795d6766a39 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Expressions/VariableReference.cs b/Runtime/SassyPatching/Nodes/Expressions/VariableReference.cs new file mode 100644 index 0000000..89a30d8 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/VariableReference.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Expressions +{ + /// + /// Represents a reference to a variable within the current environment + /// + public class VariableReference : Expression + { + /// + /// The variable being referenced + /// + public readonly string VariableName; + internal VariableReference(Coordinate c, string variableName) : base(c) + { + VariableName = variableName; + } + + /// + public override DataValue Compute(Environment environment) + { + try + { + return environment[VariableName]; + } + catch (KeyNotFoundException keyNotFoundException) + { + throw new InvalidVariableReferenceException(Coordinate, + $"${VariableName} does not exist in the current scope"); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Expressions/VariableReference.cs.meta b/Runtime/SassyPatching/Nodes/Expressions/VariableReference.cs.meta new file mode 100644 index 0000000..79ef00f --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Expressions/VariableReference.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a04effba849d2d042ac4fa64f4006818 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Indexers.meta b/Runtime/SassyPatching/Nodes/Indexers.meta new file mode 100644 index 0000000..90c5db1 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Indexers.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 22b1ac071009fa14eaad44d21f4df2ea +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Indexers/EverythingIndexer.cs b/Runtime/SassyPatching/Nodes/Indexers/EverythingIndexer.cs new file mode 100644 index 0000000..6a81334 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Indexers/EverythingIndexer.cs @@ -0,0 +1,7 @@ +namespace PatchManager.SassyPatching.Nodes.Indexers +{ + public class EverythingIndexer : Indexer + { + public EverythingIndexer(Coordinate c) : base(c) { } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Indexers/EverythingIndexer.cs.meta b/Runtime/SassyPatching/Nodes/Indexers/EverythingIndexer.cs.meta new file mode 100644 index 0000000..ee0721b --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Indexers/EverythingIndexer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3081d72d1f270c240a7d1f6ee81c41b1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Indexers/Indexer.cs b/Runtime/SassyPatching/Nodes/Indexers/Indexer.cs new file mode 100644 index 0000000..5bd300d --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Indexers/Indexer.cs @@ -0,0 +1,19 @@ +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Indexers +{ + /// + /// Represents a field indexer + /// + public abstract class Indexer : Node + { + internal Indexer(Coordinate c) : base(c) + { + } + + /// + public override void ExecuteIn(Environment environment) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Indexers/Indexer.cs.meta b/Runtime/SassyPatching/Nodes/Indexers/Indexer.cs.meta new file mode 100644 index 0000000..93fd023 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Indexers/Indexer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8c038fee3b495434d930e3968ff366e6 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Indexers/SingleIndexer.cs b/Runtime/SassyPatching/Nodes/Indexers/SingleIndexer.cs new file mode 100644 index 0000000..b524f61 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Indexers/SingleIndexer.cs @@ -0,0 +1,13 @@ +using PatchManager.SassyPatching.Nodes.Expressions; + +namespace PatchManager.SassyPatching.Nodes.Indexers +{ + public class SingleIndexer : Indexer + { + public SingleIndexer(Coordinate c, Expression index) : base(c) + { + Index = index; + } + public Expression Index { get; } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Indexers/SingleIndexer.cs.meta b/Runtime/SassyPatching/Nodes/Indexers/SingleIndexer.cs.meta new file mode 100644 index 0000000..32cbd1a --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Indexers/SingleIndexer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e62dd7335989fe14d8bcdae570b65139 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/KeyValueNode.cs b/Runtime/SassyPatching/Nodes/KeyValueNode.cs new file mode 100644 index 0000000..5d2df0b --- /dev/null +++ b/Runtime/SassyPatching/Nodes/KeyValueNode.cs @@ -0,0 +1,31 @@ +using PatchManager.SassyPatching.Nodes.Expressions; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes +{ + /// + /// A node representing a Key/Value pair in an Objects definition + /// + public class KeyValueNode : Node + { + /// + /// They field to be defined + /// + public readonly string Key; + /// + /// A node representing the value of the field + /// + public readonly Expression Value; + + internal KeyValueNode(Coordinate c, string key, Expression value) : base(c) + { + Key = key; + Value = value; + } + + /// + public override void ExecuteIn(Environment environment) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/KeyValueNode.cs.meta b/Runtime/SassyPatching/Nodes/KeyValueNode.cs.meta new file mode 100644 index 0000000..e0e29a2 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/KeyValueNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c00da9d9da3f3fe4da1fc30c6754c704 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Node.cs b/Runtime/SassyPatching/Nodes/Node.cs new file mode 100644 index 0000000..a29acda --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Node.cs @@ -0,0 +1,30 @@ +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes +{ + /// + /// An abstract class representing a node in the tree of a patch file + /// + public abstract class Node + { + /// + /// The location of this node + /// + public readonly Coordinate Coordinate; + + /// + /// Creates a new node at a location + /// + /// The location of the node + internal Node(Coordinate c) + { + Coordinate = c; + } + + /// + /// Execute this node in the given environment + /// + /// The given environment + public abstract void ExecuteIn(Environment environment); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Node.cs.meta b/Runtime/SassyPatching/Nodes/Node.cs.meta new file mode 100644 index 0000000..3f763ee --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Node.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 38709da266100064b92d9b441012c4b3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/SassyPatch.cs b/Runtime/SassyPatching/Nodes/SassyPatch.cs new file mode 100644 index 0000000..aeb6715 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/SassyPatch.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes +{ + /// + /// The top level node of a patch file, represents the entire file + /// + public class SassyPatch : Node + { + /// + /// The list of statements in this patch + /// + public readonly List Children; + + internal SassyPatch(Coordinate c, List children) : base(c) + { + Children = children; + } + + /// + public override void ExecuteIn(Environment environment) + { + foreach (var child in Children) + { + child.ExecuteIn(environment); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/SassyPatch.cs.meta b/Runtime/SassyPatching/Nodes/SassyPatch.cs.meta new file mode 100644 index 0000000..2ca42eb --- /dev/null +++ b/Runtime/SassyPatching/Nodes/SassyPatch.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ea66ca3b08f2fe9488512ab36a143558 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors.meta b/Runtime/SassyPatching/Nodes/Selectors.meta new file mode 100644 index 0000000..a2dccbf --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0b3d3907f7f00e245baa61ffd5cd9a59 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/ChildSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/ChildSelector.cs new file mode 100644 index 0000000..36d1f06 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/ChildSelector.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selector that selects children of a selectable that match a selector + /// + public class ChildSelector : Selector + { + /// + /// The selector to get the parent selectables + /// + public readonly Selector Parent; + /// + /// The selector to match children with + /// + public readonly Selector Child; + internal ChildSelector(Coordinate c, Selector parent, Selector child) : base(c) + { + Parent = parent; + Child = child; + } + + /// + public override List SelectAll(List selectables) => + SelectChildren(Parent.SelectAll(selectables)); + + private List SelectChildren(List selectedParents) + { + + List result = new(); + // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator + foreach (var selectable in selectedParents) + { + // We are going to get every child of this selectable + var allChildren = Child.SelectAll(selectable.Selectable.SelectEverything().Select(x => new SelectableWithEnvironment + { + Selectable = x, + Environment = new Environment(selectable.Environment.GlobalEnvironment, selectable.Environment) + }).ToList()); + result = SelectionUtilities.CombineSelections(result, allChildren); + } + return result; + } + + /// + public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) => + SelectChildren(Parent.SelectAllTopLevel(type, name, data, baseEnvironment, out rulesetMatchingObject)); + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) => + SelectChildren(Parent.CreateNew(rulesetArguments, baseEnvironment, out newAsset)); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/ChildSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/ChildSelector.cs.meta new file mode 100644 index 0000000..130afdc --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/ChildSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 095c3bfcf4774024d8e27c4d3dd237b8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/ClassCaptureSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/ClassCaptureSelector.cs new file mode 100644 index 0000000..7ef7e73 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/ClassCaptureSelector.cs @@ -0,0 +1,64 @@ +using System; +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Utility; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + public class ClassCaptureSelector : Selector + { + public readonly string ClassName; + public List Captures; + internal ClassCaptureSelector(Coordinate c, string className, List captures) : base(c) + { + ClassName = className; + Captures = captures; + } + + /// + public override List SelectAll(List selectableWithEnvironments) + { + List newList = new(); + foreach (var selectableWithEnvironment in selectableWithEnvironments) + { + var interpolated = ""; + try + { + interpolated = ClassName.Interpolate(selectableWithEnvironment.Environment); + } + catch (Exception e) + { + throw new InterpolationException(Coordinate, e.Message); + } + + if (selectableWithEnvironment.Selectable.MatchesClass(interpolated,out var value)) + { + selectableWithEnvironment.Environment["current"] = value; + foreach (var node in Captures) + { + node.ExecuteIn(selectableWithEnvironment.Environment); + } + selectableWithEnvironment.Environment.ScopedValues.Remove("current"); + newList.Add(selectableWithEnvironment); + } + } + return newList; + } + + /// + public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) + { + rulesetMatchingObject = null; + return new(); + } + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) + { + newAsset = null; + return new(); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/ClassCaptureSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/ClassCaptureSelector.cs.meta new file mode 100644 index 0000000..ee6d04e --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/ClassCaptureSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 22cdae7ca12cf844a8b04eaca5430ef0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/ClassSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/ClassSelector.cs new file mode 100644 index 0000000..1df1a7e --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/ClassSelector.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Utility; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selector that selects selectables that have a class + /// + public class ClassSelector : Selector + { + /// + /// The class to select against + /// + public readonly string ClassName; + internal ClassSelector(Coordinate c, string className) : base(c) + { + ClassName = className; + } + + /// + public override List SelectAll(List selectableWithEnvironments) + { + return selectableWithEnvironments.Where(selectable => selectable.Selectable.MatchesClass(ClassName.Interpolate(selectable.Environment))).ToList(); + } + + /// + public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) + { + rulesetMatchingObject = null; + return new(); + } + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) + { + newAsset = null; + return new(); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/ClassSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/ClassSelector.cs.meta new file mode 100644 index 0000000..7694336 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/ClassSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 160549b738cdf394dba010a742eab357 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/CombinationSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/CombinationSelector.cs new file mode 100644 index 0000000..a4d7aeb --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/CombinationSelector.cs @@ -0,0 +1,84 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selector that selects all selectables that get selected by any of the selectors contained within + /// + public class CombinationSelector : Selector + { + /// + /// The list of selectors to get the combination selection of + /// + public readonly List Selectors; + internal CombinationSelector(Coordinate c, Selector lhs, Selector rhs) : base(c) + { + Selectors = new(); + if (lhs is CombinationSelector lcs) + { + Selectors.AddRange(lcs.Selectors); + } + else + { + Selectors.Add(lhs); + } + + if (rhs is CombinationSelector rcs) + { + Selectors.AddRange(rcs.Selectors); + } + else + { + Selectors.Add(rhs); + } + } + + /// + public override List SelectAll(List selectableWithEnvironments) + { + var result = new List(); + // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator + foreach (var selector in Selectors) + { + result = SelectionUtilities.CombineSelections(result, selector.SelectAll(selectableWithEnvironments)); + } + return result; + } + + /// + public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) + { + var start = new List(); + rulesetMatchingObject = null; + foreach (var selector in Selectors) + { + // ReSharper disable once IdentifierTypo + start = SelectionUtilities.CombineSelections(start,selector.SelectAllTopLevel(type, name, data,baseEnvironment, out var rsmo)); + if (rsmo != null && rulesetMatchingObject == null) + { + rulesetMatchingObject = rsmo; + } + } + return start; + } + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) + { + var start = new List(); + newAsset = null; + foreach (var selector in Selectors) + { + start = SelectionUtilities.CombineSelections(start, selector.CreateNew(rulesetArguments,baseEnvironment, out var na)); + if (na != null && newAsset == null) + { + newAsset = na; + } + } + + return start; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/CombinationSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/CombinationSelector.cs.meta new file mode 100644 index 0000000..80210dd --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/CombinationSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dba63a361f009904cb730cfc1af7fe3f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/ElementAdditionSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/ElementAdditionSelector.cs new file mode 100644 index 0000000..83d4643 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/ElementAdditionSelector.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Utility; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selector that adds an element to a selectable and selects it + /// + public class ElementAdditionSelector : Selector + { + /// + /// The element type to add to the selectable + /// + public string ElementName; + internal ElementAdditionSelector(Coordinate c, string elementName) : base(c) + { + ElementName = elementName; + } + + /// + public override List SelectAll(List selectableWithEnvironments) + { + try + { + List result = new(); + foreach (var selectable in selectableWithEnvironments) + { + var interpolated = ""; + try + { + interpolated = ElementName.Interpolate(selectable.Environment); + } + catch (Exception e) + { + throw new InterpolationException(Coordinate, e.Message); + } + var addedElement = selectable.Selectable.AddElement(interpolated); + result.Add(new SelectableWithEnvironment + { + Selectable = addedElement, + Environment = new Environment(selectable.Environment.GlobalEnvironment,selectable.Environment) + }); + } + + return result; + } + catch (Exception e) + { + throw new InterpreterException(Coordinate, e.ToString()); + } + } + + /// + public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) + { + rulesetMatchingObject = null; + return new(); + } + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) + { + newAsset = null; + return new(); + + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/ElementAdditionSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/ElementAdditionSelector.cs.meta new file mode 100644 index 0000000..b3eb176 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/ElementAdditionSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 52e818875ac4fe3439ca6218d3f35713 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/ElementSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/ElementSelector.cs new file mode 100644 index 0000000..77d8749 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/ElementSelector.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Utility; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selector that selects all selectables that are an element type + /// + public class ElementSelector : Selector + { + /// + /// The element type to select + /// + public readonly string ElementName; + internal ElementSelector(Coordinate c, string elementName) : base(c) + { + ElementName = elementName; + } + + /// + public override List SelectAll(List selectableWithEnvironments) + { + return selectableWithEnvironments.Where(selectable => + { + var interpolated = ""; + try + { + interpolated = ElementName.Interpolate(selectable.Environment); + } + catch (Exception e) + { + throw new InterpolationException(Coordinate, e.Message); + } + + var result = selectable.Selectable.MatchesElement(interpolated); + return result; + }).ToList(); + } + + /// + public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) + { + rulesetMatchingObject = null; + return new(); + } + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) + { + newAsset = null; + return new(); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/ElementSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/ElementSelector.cs.meta new file mode 100644 index 0000000..ed6d8e4 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/ElementSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5bdd93c7de0303d43b22c708b4081712 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/EnsureSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/EnsureSelector.cs new file mode 100644 index 0000000..6b5cc01 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/EnsureSelector.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Utility; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selector that adds an element to a selectable and selects it + /// + public class EnsureSelector : Selector + { + /// + /// The element type to add to the selectable + /// + public string ElementName; + internal EnsureSelector(Coordinate c, string elementName) : base(c) + { + ElementName = elementName; + } + + /// + public override List SelectAll(List selectableWithEnvironments) + { + try + { + var baseList = selectableWithEnvironments.Where(selectable => + { + var interpolated = ""; + try + { + interpolated = ElementName.Interpolate(selectable.Environment); + } + catch (Exception e) + { + throw new InterpolationException(Coordinate, e.Message); + } + var result = selectable.Selectable.MatchesElement(interpolated); + return result; + }).ToList(); + // return baseList.Count == 0 ? selectables.Select(selectable => selectable.AddElement(ElementName)).ToList() : baseList; + if (baseList.Count == 0) + { + foreach (var selectable in selectableWithEnvironments) + { + var interpolated = ""; + try + { + interpolated = ElementName.Interpolate(selectable.Environment); + } + catch (Exception e) + { + throw new InterpolationException(Coordinate, e.Message); + } + var addedElement = selectable.Selectable.AddElement(interpolated); + baseList.Add(new SelectableWithEnvironment + { + Selectable = addedElement, + Environment = new Environment(selectable.Environment.GlobalEnvironment,selectable.Environment) + }); + } + } + return baseList; + } + catch (Exception e) + { + throw new InterpreterException(Coordinate, e.ToString()); + } + } + + /// + public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) + { + rulesetMatchingObject = null; + return new(); + } + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) + { + newAsset = null; + return new(); + + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/EnsureSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/EnsureSelector.cs.meta new file mode 100644 index 0000000..22421a6 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/EnsureSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 300e6fd2df1e1ac499814315923fc1d7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/IntersectionSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/IntersectionSelector.cs new file mode 100644 index 0000000..66c6899 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/IntersectionSelector.cs @@ -0,0 +1,72 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selector that selects all selectables that get selected by all of the selectors contained within + /// + public class IntersectionSelector : Selector + { + /// + /// The list of selectors to get the intersection selection of + /// + public readonly List Selectors; + internal IntersectionSelector(Coordinate c, Selector lhs, Selector rhs) : base(c) + { + Selectors = new(); + if (lhs is IntersectionSelector lis) + { + Selectors.AddRange(lis.Selectors); + } + else + { + Selectors.Add(lhs); + } + + if (rhs is IntersectionSelector ris) + { + Selectors.AddRange(ris.Selectors); + } + else + { + Selectors.Add(rhs); + } + } + + /// + public override List SelectAll(List selectableWithEnvironments) + { + // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator + foreach (var selector in Selectors) + { + selectableWithEnvironments = SelectionUtilities.IntersectSelections(selectableWithEnvironments, selector.SelectAll(selectableWithEnvironments)); + } + return selectableWithEnvironments; + } + + private List SelectAllSkippingFirst(List selectables) + { + for (var i = 1; i < Selectors.Count; i++) + { + selectables = SelectionUtilities.IntersectSelections(selectables, Selectors[i].SelectAll(selectables)); + } + return selectables; + } + + /// + public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) + { + var start = Selectors[0].SelectAllTopLevel(type, name, data, baseEnvironment, out rulesetMatchingObject); + return SelectAllSkippingFirst(start); + } + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) + { + var start = Selectors[0].CreateNew(rulesetArguments,baseEnvironment, out newAsset); + return SelectAllSkippingFirst(start); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/IntersectionSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/IntersectionSelector.cs.meta new file mode 100644 index 0000000..9f800ae --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/IntersectionSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a85de2744f791e4a8bb3ad5e41c8583 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/NameSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/NameSelector.cs new file mode 100644 index 0000000..d296ccc --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/NameSelector.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Utility; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selector that matches selectables that have a name that matches a name pattern + /// + public class NameSelector : Selector + { + /// + /// The name pattern to match against, can contain */? wildcards + /// + public readonly string NamePattern; + internal NameSelector(Coordinate c, string namePattern) : base(c) + { + NamePattern = namePattern; + } + + /// + public override List SelectAll(List selectableWithEnvironments) + { + return selectableWithEnvironments.Where(selectable => selectable.Selectable.MatchesName(NamePattern.Interpolate(selectable.Environment))).ToList(); + } + + /// + public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) + { + rulesetMatchingObject = null; + return new(); + } + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) + { + newAsset = null; + return new(); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/NameSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/NameSelector.cs.meta new file mode 100644 index 0000000..d75aca4 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/NameSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 53605d85a63d65b4787f959c50510152 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/RulesetSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/RulesetSelector.cs new file mode 100644 index 0000000..f99f7fa --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/RulesetSelector.cs @@ -0,0 +1,79 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selector that defines the ruleset that following selectors follow + /// + public class RulesetSelector : Selector + { + /// + /// The name of the ruleset + /// + public readonly string RulesetName; + internal RulesetSelector(Coordinate c, string rulesetName) : base(c) + { + RulesetName = rulesetName; + } + + /// + public override List SelectAll(List selectableWithEnvironments) + { + return new(); + } + + /// + public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) + { + if (!Universe.RuleSets.TryGetValue(RulesetName, out var ruleSet)) + { + throw new InterpreterException(Coordinate, $"Ruleset: {RulesetName} does not exist!"); + } + + if (ruleSet.Matches(type)) + { + rulesetMatchingObject = ruleSet.ConvertToSelectable(type, name,data); + if (rulesetMatchingObject != null) + { + return + new List + { + new() + { + Selectable = rulesetMatchingObject, + Environment = new Environment(baseEnvironment.GlobalEnvironment, baseEnvironment) + } + }; + } + } + rulesetMatchingObject = null; + return new List { }; + + } + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) + { + if (!Universe.RuleSets.TryGetValue(RulesetName, out var ruleSet)) + { + throw new InterpreterException(Coordinate, $"Ruleset: {RulesetName} does not exist!"); + } + + var newObject = ruleSet.CreateNew(rulesetArguments); + newAsset = newObject; + return + new List + { + new() + { + Selectable = newAsset.Selectable, + Environment = new Environment(baseEnvironment.GlobalEnvironment, baseEnvironment) + } + }; + + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/RulesetSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/RulesetSelector.cs.meta new file mode 100644 index 0000000..f0b1d7e --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/RulesetSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 53dfe32ef8e1734429879c31666984bb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/Selector.cs b/Runtime/SassyPatching/Nodes/Selectors/Selector.cs new file mode 100644 index 0000000..1396dbb --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/Selector.cs @@ -0,0 +1,50 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selector node + /// + public abstract class Selector : Node + { + internal Selector(Coordinate c) : base(c) + { + } + + /// + /// Select all that match this selector from the list of selectables + /// + /// All the selectables to match + /// A list of selections + public abstract List SelectAll(List selectables); + + /// + /// Select all that match this selector from the type and data + /// + /// The type, e.g. parts_data + /// The name of the data + /// The data, a textual representation of the data + /// The base environment to create the selectables in + /// The found object that matches the ruleset + /// A list of all selections from the data + public abstract List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject); + + + /// + /// Create a new asset (flows up until the ruleset statement) + /// + /// The arguments to the ruleset + /// The reference to the newly created asset + /// The base environment to create the selectables in + /// The new assets selectables + public abstract List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset); + + /// + public override void ExecuteIn(Environment environment) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/Selector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/Selector.cs.meta new file mode 100644 index 0000000..3147130 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/Selector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 36e8b4e8366c9ba4db42bef6f537d81d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/WildcardSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/WildcardSelector.cs new file mode 100644 index 0000000..1ec64d4 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/WildcardSelector.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selection action that matches all selectables + /// + public class WildcardSelector : Selector + { + internal WildcardSelector(Coordinate c) : base(c) + { + } + + /// + public override List SelectAll(List selectableWithEnvironments) + { + return selectableWithEnvironments; + } + + /// + public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) + { + rulesetMatchingObject = null; + return new(); + } + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) + { + newAsset = null; + return new(); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/WildcardSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/WildcardSelector.cs.meta new file mode 100644 index 0000000..576bc36 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/WildcardSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b8d612e407ebca1449dd755de5892a94 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/WithoutClassSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/WithoutClassSelector.cs new file mode 100644 index 0000000..0246652 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/WithoutClassSelector.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Utility; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selector that matches selectables that don't have the class defined in this + /// + public class WithoutClassSelector : Selector + { + /// + /// The class to match against + /// + public readonly string ClassName; + internal WithoutClassSelector(Coordinate c, string className) : base(c) + { + ClassName = className; + } + + /// + public override List SelectAll(List selectableWithEnvironments) + { + return selectableWithEnvironments.Where(selectable => !selectable.Selectable.MatchesClass(ClassName.Interpolate(selectable.Environment))).ToList(); + } + + /// + public override List SelectAllTopLevel(string type,string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) + { + rulesetMatchingObject = null; + return new(); + } + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) + { + newAsset = null; + return new(); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/WithoutClassSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/WithoutClassSelector.cs.meta new file mode 100644 index 0000000..d96f71f --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/WithoutClassSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0a85c4202d6f0af43aff61306e932d5d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Selectors/WithoutNameSelector.cs b/Runtime/SassyPatching/Nodes/Selectors/WithoutNameSelector.cs new file mode 100644 index 0000000..13f37dd --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/WithoutNameSelector.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Utility; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Selectors +{ + /// + /// Represents a selector that matches selectables that don't have a name that matches a name pattern + /// + public class WithoutNameSelector : Selector + { + /// + /// The name pattern to match against, can contain */? wildcards + /// + public readonly string NamePattern; + internal WithoutNameSelector(Coordinate c, string namePattern) : base(c) + { + NamePattern = namePattern; + } + + /// + public override List SelectAll(List selectableWithEnvironments) + { + return selectableWithEnvironments.Where(selectable => !selectable.Selectable.MatchesName(NamePattern.Interpolate(selectable.Environment))).ToList(); + } + + /// + public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) + { + rulesetMatchingObject = null; + return new(); + } + + public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) + { + newAsset = null; + return new(); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Selectors/WithoutNameSelector.cs.meta b/Runtime/SassyPatching/Nodes/Selectors/WithoutNameSelector.cs.meta new file mode 100644 index 0000000..d8dd592 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Selectors/WithoutNameSelector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b0e2076c6c1c9c94ca491b358fdc5e30 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements.meta b/Runtime/SassyPatching/Nodes/Statements.meta new file mode 100644 index 0000000..514ce6e --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 795940f32402f7141a54f42f208df15f +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/Conditional.cs b/Runtime/SassyPatching/Nodes/Statements/Conditional.cs new file mode 100644 index 0000000..7aaa6d1 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/Conditional.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Nodes.Expressions; +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements +{ + /// + /// Represents a conditional (if-else) statement + /// + public class Conditional : Node, ISelectionAction + { + /// + /// The condition that is being tested + /// + public readonly Expression Condition; + /// + /// The list of nodes to be executed upon a truthy result + /// + public readonly List Body; + /// + /// The node to be executed upon a falsy result, may not exist + /// + public readonly Node? Else; + + internal Conditional(Coordinate c, Expression condition, List body, Node? @else = null) : base(c) + { + Condition = condition; + Body = body; + Else = @else; + } + + /// + public override void ExecuteIn(Environment environment) + { + if (Condition.Compute(environment).Truthy) + { + foreach (var child in Body) + { + child.ExecuteIn(environment); + } + } + else + { + Else?.ExecuteIn(environment); + } + } + + /// + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) + { + if (Condition.Compute(environment).Truthy) + { + foreach (var child in Body) + { + if (child is ISelectionAction selectionAction) + { + selectionAction.ExecuteOn(environment, selectable, modifiable); + } + else + { + child.ExecuteIn(environment); + } + } + } + else + { + if (Else is ISelectionAction selectionAction) + { + selectionAction.ExecuteOn(environment, selectable, modifiable); + } + else + { + Else?.ExecuteIn(environment); + } + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/Conditional.cs.meta b/Runtime/SassyPatching/Nodes/Statements/Conditional.cs.meta new file mode 100644 index 0000000..a96b0d8 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/Conditional.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 57e180e01cfd8134e8105e98e65e4c8e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/Each.cs b/Runtime/SassyPatching/Nodes/Statements/Each.cs new file mode 100644 index 0000000..53cbeba --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/Each.cs @@ -0,0 +1,224 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Nodes.Expressions; +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements +{ + /// + /// Represents a loop that iterates over a list/dictionary/string + /// + public class Each : Node, ISelectionAction + { + /// + /// The variable to store the keys of iterations of this list node (optional) + /// + public readonly string? KeyName; + /// + /// Where to store the values of the iterations of this list node + /// + public readonly string ValueName; + /// + /// The expression that returns what is being iterated over + /// + public readonly Expression Iterator; + public readonly List Children; + + internal Each(Coordinate c, string? keyName, string valueName, Expression iterator, List children) : base(c) + { + Iterator = iterator; + Children = children; + ValueName = valueName; + KeyName = keyName; + } + + /// + public override void ExecuteIn(Environment environment) + { + var value = Iterator.Compute(environment); + if (value.IsList) + { + EachList(environment, value); + return; + } + + if (value.IsString) + { + EachString(environment, value); + return; + } + + if (value.IsDictionary) + { + EachDictionary(environment, value); + return; + } + + throw new InterpreterException(Coordinate, + $"cannot iterate over a value of type {value.Type.ToString().ToLowerInvariant()}"); + } + + private void EachDictionary(Environment environment, DataValue value) + { + foreach (var (k, v) in value.Dictionary) + { + if (KeyName != null) + { + environment[KeyName] = k; + } + + environment[ValueName] = v; + ExecuteChildren(environment); + } + } + + private void EachString(Environment environment, DataValue value) + { + if (KeyName != null) + { + for (var i = 0; i < value.String.Length; i++) + { + environment[KeyName] = i; + environment[ValueName] = value.String[i]; + ExecuteChildren(environment); + } + } + else + { + foreach (var v in value.String) + { + environment[ValueName] = v; + ExecuteChildren(environment); + } + } + } + + private void EachList(Environment environment, DataValue value) + { + if (KeyName != null) + { + for (var i = 0; i < value.List.Count; i++) + { + environment[KeyName] = i; + environment[ValueName] = value.List[i]; + ExecuteChildren(environment); + } + } + else + { + foreach (var v in value.List) + { + environment[ValueName] = v; + ExecuteChildren(environment); + } + } + } + + private void ExecuteChildren(Environment environment) + { + foreach (var child in Children) + { + child.ExecuteIn(environment); + } + } + + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) + { + var value = Iterator.Compute(environment); + if (value.IsList) + { + EachList(environment, selectable, modifiable, value); + return; + } + + if (value.IsString) + { + EachString(environment, selectable, modifiable, value); + return; + } + + if (value.IsDictionary) + { + EachDictionary(environment, selectable, modifiable, value); + return; + } + + throw new InterpreterException(Coordinate, + $"cannot iterate over a value of type {value.Type.ToString().ToLowerInvariant()}"); + } + + private void EachDictionary(Environment environment, ISelectable selectable, IModifiable modifiable, DataValue value) + { + foreach (var (k, v) in value.Dictionary) + { + if (KeyName != null) + { + environment[KeyName] = k; + } + + environment[ValueName] = v; + ExecuteChildren(environment,selectable,modifiable); + } + } + + private void EachString(Environment environment, ISelectable selectable, IModifiable modifiable, DataValue value) + { + if (KeyName != null) + { + for (var i = 0; i < value.String.Length; i++) + { + environment[KeyName] = i; + environment[ValueName] = value.String[i]; + ExecuteChildren(environment,selectable,modifiable); + } + } + else + { + foreach (var v in value.String) + { + environment[ValueName] = v; + ExecuteChildren(environment,selectable,modifiable); + } + } + } + + private void EachList(Environment environment, ISelectable selectable, IModifiable modifiable, DataValue value) + { + if (KeyName != null) + { + for (var i = 0; i < value.List.Count; i++) + { + environment[KeyName] = i; + environment[ValueName] = value.List[i]; + ExecuteChildren(environment,selectable,modifiable); + } + } + else + { + foreach (var v in value.List) + { + environment[ValueName] = v; + ExecuteChildren(environment,selectable,modifiable); + } + } + } + + private void ExecuteChildren(Environment environment, ISelectable selectable, IModifiable modifiable) + { + foreach (var child in Children) + { + if (child is ISelectionAction selectionAction) + { + selectionAction.ExecuteOn(environment,selectable,modifiable); + } + else + { + child.ExecuteIn(environment); + } + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/Each.cs.meta b/Runtime/SassyPatching/Nodes/Statements/Each.cs.meta new file mode 100644 index 0000000..ac8a2ae --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/Each.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 22822b25b4df77044a5143480f68e753 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/For.cs b/Runtime/SassyPatching/Nodes/Statements/For.cs new file mode 100644 index 0000000..535a3fd --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/For.cs @@ -0,0 +1,349 @@ +using System; +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Nodes.Expressions; +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements +{ + /// + /// Represents a loop that iterates over a range of numbers + /// + public class For : Node, ISelectionAction + { + /// + /// The variable that is set to the current iteration value + /// + public readonly string VariableName; + /// + /// The starting value of the iteration + /// + public readonly Expression InitialValue; + /// + /// Whether or not the loop is inclusive in its range + /// + public readonly bool Inclusive; + /// + /// The ending value of the iteration + /// + public readonly Expression EndingValue; + /// + /// The body of the iteration + /// + public readonly List Children; + + internal For(Coordinate c, string variableName, Expression initialValue, bool inclusive, Expression endingValue, List children) : base(c) + { + VariableName = variableName; + InitialValue = initialValue; + Inclusive = inclusive; + EndingValue = endingValue; + Children = children; + } + + /// + public override void ExecuteIn(Environment environment) + { + var start = InitialValue.Compute(environment); + var end = EndingValue.Compute(environment); + if (start.IsInteger) + { + SetupIntegerIteration(environment, end, start); + return; + } + + if (start.IsReal) + { + SetupRealIteration(environment, end, start); + return; + } + + throw new InterpreterException(Coordinate, $"cannot do a for loop w/ a value that is of type {start.Type.ToString().ToLowerInvariant()}"); + } + + private void SetupRealIteration(Environment environment, DataValue end, DataValue start) + { + Func endCheck; + bool inverted; + if (end.IsReal) + { + inverted = SetupRealRealIteration(end, start, out endCheck); + } + else if (end.IsInteger) + { + inverted = SetupRealIntegerIteration(end, start, out endCheck); + } + else + { + throw new InterpreterException(Coordinate, $"cannot do a for loop through/to a value of type {end.Type.ToString().ToLowerInvariant()}"); + } + + IterateReal(environment, start.Real, inverted, endCheck); + } + + private bool SetupRealIntegerIteration(DataValue end, DataValue start, out Func endCheck) + { + bool inverted; + inverted = start.Integer > end.Integer; + if (Inclusive) + { + if (inverted) + { + endCheck = l => l < end.Integer; + } + else + { + endCheck = l => l > end.Integer; + } + } + else + { + if (inverted) + { + endCheck = l => l <= end.Integer; + } + else + { + endCheck = l => l >= end.Integer; + } + } + + return inverted; + } + + private bool SetupRealRealIteration(DataValue end, DataValue start, out Func endCheck) + { + bool inverted; + inverted = start.Integer > end.Real; + if (Inclusive) + { + if (inverted) + { + endCheck = l => l < end.Real; + } + else + { + endCheck = l => l > end.Real; + } + } + else + { + if (inverted) + { + endCheck = l => l <= end.Real; + } + else + { + endCheck = l => l >= end.Real; + } + } + + return inverted; + } + + private void SetupIntegerIteration(Environment environment, DataValue end, DataValue start) + { + Func endCheck; + bool inverted; + if (end.IsReal) + { + inverted = SetupIntegerRealIteration(end, start, out endCheck); + } + else if (end.IsInteger) + { + inverted = SetupIntegerIntegerIteration(end, start, out endCheck); + } + else + { + throw new InterpreterException(Coordinate, $"cannot do a for loop through/to a value of type {end.Type.ToString().ToLowerInvariant()}"); + } + + IterateInteger(environment, start.Integer, inverted, endCheck); + } + + private bool SetupIntegerIntegerIteration(DataValue end, DataValue start, out Func endCheck) + { + bool inverted; + inverted = start.Integer > end.Integer; + if (Inclusive) + { + if (inverted) + { + endCheck = l => l < end.Integer; + } + else + { + endCheck = l => l > end.Integer; + } + } + else + { + if (inverted) + { + endCheck = l => l <= end.Integer; + } + else + { + endCheck = l => l >= end.Integer; + } + } + + return inverted; + } + + private bool SetupIntegerRealIteration(DataValue end, DataValue start, out Func endCheck) + { + bool inverted; + inverted = start.Integer > end.Real; + if (Inclusive) + { + if (inverted) + { + endCheck = l => l < end.Real; + } + else + { + endCheck = l => l > end.Real; + } + } + else + { + if (inverted) + { + endCheck = l => l <= end.Real; + } + else + { + endCheck = l => l >= end.Real; + } + } + + return inverted; + } + + + private void IterateInteger(Environment environment, long start, bool inverted, Func end) + { + while (!end(start)) + { + environment[VariableName] = start; + ExecuteChildren(environment); + start += inverted ? -1 : 1; + } + } + + private void IterateReal(Environment environment, double start, bool inverted, Func end) + { + while (!end(start)) + { + environment[VariableName] = start; + ExecuteChildren(environment); + start += inverted ? -1 : 1; + } + } + + + private void ExecuteChildren(Environment environment) + { + foreach (var child in Children) + { + child.ExecuteIn(environment); + } + } + + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) + { + var start = InitialValue.Compute(environment); + var end = EndingValue.Compute(environment); + if (start.IsInteger) + { + SetupIntegerIteration(environment, selectable, modifiable, end, start); + return; + } + + if (start.IsReal) + { + SetupRealIteration(environment, selectable, modifiable, end, start); + return; + } + + throw new InterpreterException(Coordinate, $"cannot do a for loop w/ a value that is of type {start.Type.ToString().ToLowerInvariant()}"); + } + private void SetupRealIteration(Environment environment, ISelectable selectable, IModifiable modifiable, DataValue end, DataValue start) + { + Func endCheck; + bool inverted; + if (end.IsReal) + { + inverted = SetupRealRealIteration(end, start, out endCheck); + } + else if (end.IsInteger) + { + inverted = SetupRealIntegerIteration(end, start, out endCheck); + } + else + { + throw new InterpreterException(Coordinate, $"cannot do a for loop through/to a value of type {end.Type.ToString().ToLowerInvariant()}"); + } + + IterateReal(environment, selectable, modifiable, start.Real, inverted, endCheck); + } + + private void SetupIntegerIteration(Environment environment, ISelectable selectable, IModifiable modifiable, DataValue end, DataValue start) + { + Func endCheck; + bool inverted; + if (end.IsReal) + { + inverted = SetupIntegerRealIteration(end, start, out endCheck); + } + else if (end.IsInteger) + { + inverted = SetupIntegerIntegerIteration(end, start, out endCheck); + } + else + { + throw new InterpreterException(Coordinate, $"cannot do a for loop through/to a value of type {end.Type.ToString().ToLowerInvariant()}"); + } + + IterateInteger(environment, selectable, modifiable, start.Integer, inverted, endCheck); + } + + + private void IterateInteger(Environment environment, ISelectable selectable, IModifiable modifiable, long start, bool inverted, Func end) + { + while (!end(start)) + { + environment[VariableName] = start; + ExecuteChildren(environment, selectable, modifiable); + start += inverted ? -1 : 1; + } + } + + private void IterateReal(Environment environment, ISelectable selectable, IModifiable modifiable, double start, bool inverted, Func end) + { + while (!end(start)) + { + environment[VariableName] = start; + ExecuteChildren(environment, selectable, modifiable); + start += inverted ? -1 : 1; + } + } + private void ExecuteChildren(Environment environment, ISelectable selectable, IModifiable modifiable) + { + foreach (var child in Children) + { + if (child is ISelectionAction selectionAction) + { + selectionAction.ExecuteOn(environment,selectable,modifiable); + } + else + { + child.ExecuteIn(environment); + } + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/For.cs.meta b/Runtime/SassyPatching/Nodes/Statements/For.cs.meta new file mode 100644 index 0000000..df7625b --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/For.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 246d5bc5091f55c4695c6b8d85d308ee +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/FunctionLevel.meta b/Runtime/SassyPatching/Nodes/Statements/FunctionLevel.meta new file mode 100644 index 0000000..e041be9 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/FunctionLevel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fdd38abce60102c45b96488e7c872c34 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/FunctionLevel/Return.cs b/Runtime/SassyPatching/Nodes/Statements/FunctionLevel/Return.cs new file mode 100644 index 0000000..58a22fd --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/FunctionLevel/Return.cs @@ -0,0 +1,27 @@ +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Nodes.Expressions; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.FunctionLevel +{ + /// + /// Represents a function return statement + /// + public class Return : Node + { + /// + /// The value to be returned from the function + /// + public readonly Expression ReturnedValue; + internal Return(Coordinate c, Expression returnedValue) : base(c) + { + ReturnedValue = returnedValue; + } + + /// + public override void ExecuteIn(Environment environment) + { + throw new FunctionReturnException(ReturnedValue.Compute(environment)); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/FunctionLevel/Return.cs.meta b/Runtime/SassyPatching/Nodes/Statements/FunctionLevel/Return.cs.meta new file mode 100644 index 0000000..5777521 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/FunctionLevel/Return.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e742ba7ce1a7e604c8ea51be666f3d0d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionBlock.cs b/Runtime/SassyPatching/Nodes/Statements/SelectionBlock.cs new file mode 100644 index 0000000..11df91e --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionBlock.cs @@ -0,0 +1,204 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Nodes.Attributes; +using PatchManager.SassyPatching.Nodes.Expressions; +using PatchManager.SassyPatching.Nodes.Selectors; +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements +{ + /// + /// Represents a selection block + /// + public class SelectionBlock : Node, ISelectionAction + { + /// + /// The attributes applied to this selection block + /// + public readonly List Attributes; + /// + /// The selector that this selection block matches + /// + public readonly Selector Selector; + /// + /// The actions to be taken upon a match + /// + public readonly List Actions; + + internal SelectionBlock(Coordinate c, List attributes, Selector selector, List actions) : base(c) + { + Attributes = attributes; + Selector = selector; + Actions = actions; + } + + + /// + /// Execute this selection block on a dataset + /// + /// The environment that contains this selection block + /// The type of dataset this is being executed (e.g. parts_data) + /// The dataset to execute this patch on + public bool ExecuteFresh(Environment snapshot, string datasetType, string name, ref string dataset) + { + // var subEnvironment = new Environment(snapshot.GlobalEnvironment, snapshot); + var selections = Selector.SelectAllTopLevel(datasetType, name, dataset, snapshot, out var rulesetMatchingObject); + + if (rulesetMatchingObject == null || selections.Count == 0) + { + return false; + } + // Get the first matching selection if there are somehow more than one + foreach (var selectable in selections) { + var modifiable = selectable.Selectable.OpenModification(); + var subEnvironment = new Environment(selectable.Environment.GlobalEnvironment, selectable.Environment); + if (modifiable != null) + { + subEnvironment["current"] = modifiable.Get(); + } + + foreach (var action in Actions) + { + if (action is ISelectionAction selectionAction) + { + selectionAction.ExecuteOn(subEnvironment, selectable.Selectable, modifiable); + } + else + { + action.ExecuteIn(subEnvironment); + } + } + + + } + var newDataSet = rulesetMatchingObject.Serialize(); + if (newDataSet == dataset) return false; + dataset = newDataSet; + return true; + + } + + public INewAsset ExecuteCreation(Environment snapshot, List arguments) + { + var selections = Selector.CreateNew(arguments, snapshot, out var resultingAsset); + foreach (var selectable in selections) { + var modifiable = selectable.Selectable.OpenModification(); + var subEnvironment = new Environment(selectable.Environment.GlobalEnvironment, selectable.Environment); + if (modifiable != null) + { + subEnvironment["current"] = modifiable.Get(); + } + + foreach (var action in Actions) + { + if (action is ISelectionAction selectionAction) + { + selectionAction.ExecuteOn(subEnvironment, selectable.Selectable, modifiable); + } + else + { + action.ExecuteIn(subEnvironment); + } + } + + } + return resultingAsset; + } + + + private void CreateGenerator(Environment environment, List arguments) + { + + foreach (var attribute in Attributes) + { + switch (attribute) + { + case RequireModAttribute requireModAttribute when + !requireModAttribute.Expression.Execute(environment.GlobalEnvironment.Universe.AllMods,environment): + return; + } + } + + var snapshot = environment.Snapshot(); + var args = arguments.Select(x => x.Compute(snapshot)).ToList(); + var generator = new SassyGenerator(snapshot, this, args); + environment.GlobalEnvironment.Universe.RegisterGenerator(generator); + } + /// + public override void ExecuteIn(Environment environment) + { + foreach (var attribute in Attributes) + { + switch (attribute) + { + case RequireModAttribute requireModAttribute when + !requireModAttribute.Expression.Execute(environment.GlobalEnvironment.Universe.AllMods,environment): + return; + case NewAttribute na: + CreateGenerator(environment, na.Arguments); + return; + } + } + var snapshot = environment.Snapshot(); + + var patcher = new SassyTextPatcher(snapshot, this); + environment.GlobalEnvironment.Universe.RegisterPatcherToUniverse(patcher); + } + + /// + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable = null) + { + foreach (var attribute in Attributes) + { + switch (attribute) + { + case RequireModAttribute requireModAttribute when + !requireModAttribute.Expression.Execute(environment.GlobalEnvironment.Universe.AllMods,environment): + return; + } + } + + var selections = Selector.SelectAll(new List { new() + { + Selectable = selectable, + Environment = new Environment(environment.GlobalEnvironment,environment.Snapshot()) + } }); + if (selections.Count == 0) return; + // Takes a snapshot of the parent in its current state + var parentValue = modifiable?.Get(); + foreach (var selection in selections) + { + ExecuteOnSingleSelection(selection.Environment, selection.Selectable, parentValue); + } + } + + private void ExecuteOnSingleSelection(Environment environment, ISelectable selection, DataValue parentDataValue) + { + var subModifiable = selection.OpenModification(); + var subEnvironment = new Environment(environment.GlobalEnvironment, environment) + { + ["current"] = selection.GetValue() + }; + + if (parentDataValue != null) + { + subEnvironment["parent"] = parentDataValue; + } + + foreach (var action in Actions) + { + if (action is ISelectionAction selectionAction) + { + selectionAction.ExecuteOn(subEnvironment, selection, subModifiable); + } + else + { + action.ExecuteIn(subEnvironment); + } + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionBlock.cs.meta b/Runtime/SassyPatching/Nodes/Statements/SelectionBlock.cs.meta new file mode 100644 index 0000000..ea0029b --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionBlock.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 09917dee9311dd04bb62f76a390b7124 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel.meta b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel.meta new file mode 100644 index 0000000..0a80aae --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4e628e53bfcadd142872c3aedf440c23 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/DeleteValue.cs b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/DeleteValue.cs new file mode 100644 index 0000000..9457fc0 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/DeleteValue.cs @@ -0,0 +1,31 @@ +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Interfaces; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel +{ + /// + /// Represents a deletion selection action + /// + public class DeleteValue : Node, ISelectionAction + { + internal DeleteValue(Coordinate c) : base(c) + { + } + + /// + public override void ExecuteIn(Environment environment) + { + } + + /// + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) + { + if (modifiable == null) + { + throw new InterpreterException(Coordinate, "Attempting to delete an unmodifiable selection"); + } + modifiable.Set(new DataValue(DataValue.DataType.Deletion)); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/DeleteValue.cs.meta b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/DeleteValue.cs.meta new file mode 100644 index 0000000..2b13562 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/DeleteValue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e02f8a7d39d47cb48b166657269efaac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/Field.cs b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/Field.cs new file mode 100644 index 0000000..09f7154 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/Field.cs @@ -0,0 +1,163 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Nodes.Expressions; +using PatchManager.SassyPatching.Nodes.Indexers; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel +{ + /// + /// Represents a field setting selection action + /// + public class Field : Node, ISelectionAction + { + /// + /// The field to be set + /// + public readonly string FieldName; + /// + /// The index into the field, if there is one + /// + public readonly List Indexers; + /// + /// The value to set the field to + /// + public readonly Expression FieldValue; + internal Field(Coordinate c, string fieldName, List indexers, Expression fieldValue) : base(c) + { + FieldName = fieldName; + Indexers = indexers; + FieldValue = fieldValue; + } + + /// + public override void ExecuteIn(Environment environment) + { + } + + /// + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) + { + if (modifiable == null) + { + throw new InterpreterException(Coordinate, "Attempting to modify an unmodifiable selection"); + } + + var current = modifiable.GetFieldValue(FieldName); + var subEnv = new Environment(environment.GlobalEnvironment, environment); + modifiable.SetFieldValue(FieldName, ComputeValues(subEnv, current)); + } + private DataValue ComputeValues(Environment subEnv, DataValue current, int layer = 0) + { + if (Indexers.Count == layer) + { + subEnv["value"] = current; + return FieldValue.Compute(subEnv); + } + + var indexer = Indexers[layer]; + switch (indexer) + { + case SingleIndexer singleIndexer: + { + var index = singleIndexer.Index.Compute(subEnv); + if (index.IsInteger) + { + return ComputeIntegerIndex(subEnv, current, layer, index, indexer); + } + + if (index.IsString) + { + return ComputeStringIndex(subEnv, current, layer, index, indexer); + } + + throw new InterpreterException(indexer.Coordinate, + $"Invalid index type {index.Type}, expected Integer or String"); + } + case EverythingIndexer everythingIndexer: + return current.Type switch + { + DataValue.DataType.List => current.List.Select(value => ComputeValues(subEnv, value, layer + 1)) + .ToList(), + DataValue.DataType.Dictionary => current.Dictionary + .Select(kv => (kv.Key, ComputeValues(subEnv, kv.Value, layer + 1))) + .ToDictionary(kv => kv.Key, kv => kv.Item2), + DataValue.DataType.None => DataValue.Null, + _ => throw new InterpreterException(everythingIndexer.Coordinate, + $"Attempting to use a `*` indexer on a value of type {current.Type}") + }; + default: + throw new InterpreterException(indexer.Coordinate, $"Unknown indexer type: {indexer.GetType()}"); + } + } + + private DataValue ComputeStringIndex( + Environment subEnv, + DataValue current, + int layer, + DataValue index, + Node indexer + ) + { + // ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault + return current.Type switch + { + DataValue.DataType.None => new Dictionary + { + [index.String] = ComputeValues(subEnv, DataValue.Null, layer + 1) + }, + DataValue.DataType.Dictionary => new Dictionary(current.Dictionary) + { + [index.String] = ComputeValues(subEnv, + current.Dictionary.TryGetValue(index.String, out var currentValue) + ? currentValue + : DataValue.Null, layer + 1), + }, + _ => throw new InterpreterException(indexer.Coordinate, + $"Attempting to index into a value of type {current.Type} with an indexer that is a String") + }; + } + + private DataValue ComputeIntegerIndex( + Environment subEnv, + DataValue current, + int layer, + DataValue index, + Node indexer + ) + { + // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault + switch (current.Type) + { + case DataValue.DataType.None: + { + var list = new List(); + for (var i = 0; i < index.Integer; i++) + { + list.Add(DataValue.Null); + } + + list.Add(ComputeValues(subEnv, DataValue.Null, layer + 1)); + return list; + } + case DataValue.DataType.List: + { + var list = new List(current.List); + while (list.Count <= (int)index.Integer) + { + list.Add(DataValue.Null); + } + + list[(int)index.Integer] = ComputeValues(subEnv, list[(int)index.Integer], layer + 1); + return list; + } + default: + throw new InterpreterException(indexer.Coordinate, + $"Attempting to index into a value of type {current.Type} with an indexer that is an Integer"); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/Field.cs.meta b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/Field.cs.meta new file mode 100644 index 0000000..cf7ef25 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/Field.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 40bb1c1357096224f8f1bc6bd8c40a96 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/ISelectionAction.cs b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/ISelectionAction.cs new file mode 100644 index 0000000..9ad2ca8 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/ISelectionAction.cs @@ -0,0 +1,20 @@ +using JetBrains.Annotations; +using PatchManager.SassyPatching.Interfaces; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel +{ + /// + /// This represents a selection action to be taken on a selection + /// + public interface ISelectionAction + { + /// + /// Execute this selection action on a selectable + /// + /// The environment that this action is taking place in + /// The selectable that this action is being acted upon + /// The modifiable state of the selectable, null if its not modifiable + public void ExecuteOn(Environment environment, ISelectable selectable, [CanBeNull] IModifiable modifiable); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/ISelectionAction.cs.meta b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/ISelectionAction.cs.meta new file mode 100644 index 0000000..96a52c0 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/ISelectionAction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7112f5bddaa18cc46b1c8394f1e0e986 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MergeValue.cs b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MergeValue.cs new file mode 100644 index 0000000..11e049e --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MergeValue.cs @@ -0,0 +1,57 @@ +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Nodes.Expressions; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel +{ + /// + /// Represents a merge selection action + /// + public class MergeValue : Node, ISelectionAction + { + /// + /// The value the selection is going to be merged with, should evaluate to a dictionary + /// + public readonly Expression Value; + internal MergeValue(Coordinate c, Expression value) : base(c) + { + Value = value; + } + + /// + public override void ExecuteIn(Environment environment) + { + } + + /// + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) + { + if (modifiable == null) + { + throw new InterpreterException(Coordinate, "Attempting to merge non modifiable selection"); + } + + var value = modifiable.Get(); + var subEnvironment = new Environment(environment.GlobalEnvironment, environment) + { + ["value"] = value + }; + var toMerge = Value.Compute(subEnvironment); + if (value.IsDictionary && toMerge.IsDictionary) + { + foreach (var kv in toMerge.Dictionary) + { + value.Dictionary[kv.Key] = kv.Value; + } + + modifiable.Set(value); + } + else + { + throw new BinaryExpressionTypeException(Coordinate, "merge", value.Type.ToString(), + toMerge.Type.ToString()); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MergeValue.cs.meta b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MergeValue.cs.meta new file mode 100644 index 0000000..7672ab1 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MergeValue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a5f6406bff099214393518a1398d1094 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinBlockInclude.cs b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinBlockInclude.cs new file mode 100644 index 0000000..0bec269 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinBlockInclude.cs @@ -0,0 +1,64 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Interfaces; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel +{ + /// + /// Represents a mixin block include (i.e. slotting actions into a mixin) + /// + public class MixinBlockInclude : Node, ISelectionAction + { + /// + /// The name of the mixin being included + /// + public readonly string MixinName; + /// + /// The list of arguments to the mixin being included + /// + public readonly List Arguments; + + /// + /// The actions to be slotted into the mixin + /// + public readonly List SlotActions; + + internal MixinBlockInclude(Coordinate c, string mixinName, List arguments, List slotActions) : base(c) + { + MixinName = mixinName; + Arguments = arguments; + SlotActions = slotActions; + } + + /// + public override void ExecuteIn(Environment environment) + { + } + + /// + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) + { + if (environment.GlobalEnvironment.AllMixins.TryGetValue(MixinName, out var mixin)) + { + try + { + var subEnv = new Environment(environment.GlobalEnvironment, environment) + { + SlotActions = SlotActions + }; + mixin.Include(subEnv,Arguments.Select(x => x.Compute(environment)).ToList(),selectable,modifiable); + } + catch (InvocationException e) + { + throw new InterpreterException(Coordinate, e.ToString()); + } + } + else + { + throw new InterpreterException(Coordinate, $"{MixinName} is not a valid mixin"); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinBlockInclude.cs.meta b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinBlockInclude.cs.meta new file mode 100644 index 0000000..46b658a --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinBlockInclude.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: aa9d1eb23dbbd2a4c84dc39f3e772516 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinInclude.cs b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinInclude.cs new file mode 100644 index 0000000..301b028 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinInclude.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Interfaces; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel +{ + /// + /// Represents a mixin inclusion + /// + public class MixinInclude : Node, ISelectionAction + { + /// + /// The name of the mixin being included + /// + public readonly string MixinName; + /// + /// The list of arguments to the mixin being included + /// + public readonly List Arguments; + + internal MixinInclude(Coordinate c, string mixinName, List arguments) : base(c) + { + MixinName = mixinName; + Arguments = arguments; + } + + /// + public override void ExecuteIn(Environment environment) + { + } + + /// + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) + { + if (environment.GlobalEnvironment.AllMixins.TryGetValue(MixinName, out var mixin)) + { + try + { + mixin.Include(environment,Arguments.Select(x => x.Compute(environment)).ToList(),selectable,modifiable); + } + catch (InvocationException e) + { + throw new InterpreterException(Coordinate, e.ToString()); + } + } + else + { + throw new InterpreterException(Coordinate, $"{MixinName} is not a valid mixin"); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinInclude.cs.meta b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinInclude.cs.meta new file mode 100644 index 0000000..76ce7a8 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinInclude.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 43c96ea2b34ff7f40a4f1b514d582466 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinSlot.cs b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinSlot.cs new file mode 100644 index 0000000..3f5029b --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinSlot.cs @@ -0,0 +1,38 @@ +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Interfaces; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel +{ + public class MixinSlot : Node, ISelectionAction + { + public MixinSlot(Coordinate c) : base(c) + { + + } + public override void ExecuteIn(Environment environment) + { + } + + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) + { + var actions = environment.SlotActions; + if (actions == null) + { + throw new InterpreterException(Coordinate, "Attempting to insert into a mixin slot without there being any actions passed for this purpose"); + } + + foreach (var action in actions) + { + if (action is ISelectionAction selectionAction) + { + selectionAction.ExecuteOn(environment, selectable, modifiable); + } + else + { + action.ExecuteIn(environment); + } + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinSlot.cs.meta b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinSlot.cs.meta new file mode 100644 index 0000000..8df0f7a --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/MixinSlot.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 951fb2c63678db144b014065399c3c89 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/SetValue.cs b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/SetValue.cs new file mode 100644 index 0000000..078a900 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/SetValue.cs @@ -0,0 +1,46 @@ +using System; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Nodes.Expressions; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel +{ + /// + /// Represents a value setting selection action + /// + public class SetValue : Node, ISelectionAction + { + /// + /// The value to set the selection to + /// + public readonly Expression Value; + internal SetValue(Coordinate c, Expression value) : base(c) + { + Value = value; + } + + /// + public override void ExecuteIn(Environment environment) + { + throw new NotImplementedException(); + } + + /// + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) + { + if (modifiable == null) + { + throw new InterpreterException(Coordinate, "Attempting to set a non modifiable selection"); + } + + var value = modifiable.Get(); + var subEnvironment = new Environment(environment.GlobalEnvironment, environment) + { + ["value"] = value + }; + var result = Value.Compute(subEnvironment); + modifiable.Set(result); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/SetValue.cs.meta b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/SetValue.cs.meta new file mode 100644 index 0000000..50e6619 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/SelectionLevel/SetValue.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b926d2bf9543e7140937c7f9baf1e8d0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel.meta b/Runtime/SassyPatching/Nodes/Statements/TopLevel.meta new file mode 100644 index 0000000..9b43935 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f9eacf81d444086448dc37c4004ec4be +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigCreation.cs b/Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigCreation.cs new file mode 100644 index 0000000..f54f9a7 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigCreation.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Nodes.Expressions; +using PatchManager.SassyPatching.Utility; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel +{ + public class ConfigCreation : Node + { + public string ConfigLabel; + public string ConfigName; + public Expression ConfigValue; + public ConfigCreation(Coordinate c, string configLabel, string configName, Expression configValue) : base(c) + { + ConfigLabel = configLabel; + ConfigName = configName; + ConfigValue = configValue; + } + public override void ExecuteIn(Environment environment) + { + var configLabel = ""; + var configName = ""; + try + { + configLabel = ConfigLabel.Interpolate(environment); + configName = ConfigName.Interpolate(environment); + } + catch (Exception e) + { + throw new InterpolationException(Coordinate, e.Message); + } + + var universe = environment.GlobalEnvironment.Universe; + if (!universe.Configs.TryGetValue(configLabel, out var label)) + label = universe.Configs[configLabel] = new Dictionary(); + label[configName] = ConfigValue.Compute(environment); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigCreation.cs.meta b/Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigCreation.cs.meta new file mode 100644 index 0000000..407a754 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigCreation.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1a5067883cedc6a4ba2ac4be7c07345f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigUpdate.cs b/Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigUpdate.cs new file mode 100644 index 0000000..9d37cef --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigUpdate.cs @@ -0,0 +1,32 @@ +using JetBrains.Annotations; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Nodes.Expressions; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel +{ + public class ConfigUpdate : Node + { + public Expression Priority; + public string Label; + public string? Name; + public Expression UpdateExpression; + public ConfigUpdate(Coordinate c, Expression priority, string label, string? name, Expression updateExpression) : base(c) + { + Priority = priority; + Label = label; + Name = name; + UpdateExpression = updateExpression; + } + public override void ExecuteIn(Environment environment) + { + var universe = environment.GlobalEnvironment.Universe; + var priority = Priority.Compute(environment); + if (!priority.IsInteger) + { + throw new InterpreterException(Coordinate, "The priority for a config update must be an integer"); + } + universe.AddConfigUpdater(priority.Integer,Label,Name,UpdateExpression,environment.Snapshot()); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigUpdate.cs.meta b/Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigUpdate.cs.meta new file mode 100644 index 0000000..94f6279 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/ConfigUpdate.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: beffc14af0947de4a9827f12fc2cb968 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/Function.cs b/Runtime/SassyPatching/Nodes/Statements/TopLevel/Function.cs new file mode 100644 index 0000000..ffe24ba --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/Function.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel +{ + /// + /// Represents a function definition + /// + public class Function : Node + { + /// + /// The name of the function + /// + public readonly string Name; + /// + /// The list of arguments the function takes + /// + public readonly List Arguments; + /// + /// The list of statements to be executed upon a function call + /// + public readonly List Body; + internal Function(Coordinate c, string name, List arguments, List body) : base(c) + { + Name = name; + Arguments = arguments; + Body = body; + } + + // Don't register functions just yet + /// + public override void ExecuteIn(Environment environment) + { + // We register this function as if its alone in its environment and cannot react to the changes of variables outside of its scope + var snapshot = environment.Snapshot(); + environment.GlobalEnvironment.AllFunctions[Name] = new SassyPatchFunction(snapshot, this); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/Function.cs.meta b/Runtime/SassyPatching/Nodes/Statements/TopLevel/Function.cs.meta new file mode 100644 index 0000000..c56d896 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/Function.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 535aa4ac9c340294e866a81e1bf71fde +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/Import.cs b/Runtime/SassyPatching/Nodes/Statements/TopLevel/Import.cs new file mode 100644 index 0000000..1414893 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/Import.cs @@ -0,0 +1,51 @@ +using System; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Utility; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel +{ + /// + /// Represents a library import + /// + public class Import : Node + { + /// + /// + /// The library being imported, can take a few formats + /// + /// + /// Local library: "name", imports a local (to the patch folder for the mod) file named "_name" or if there is any pathing it only prepends the underscore after the last slash + /// + /// + /// External library: "guid:name", imports a file from another mod (defined in the guid) named "_name" + /// + /// + /// Builtin library: "builtin:name", imports a builtin library named "name" + /// + /// + public readonly string Library; + + internal Import(Coordinate c, string library) : base(c) + { + Library = library; + } + + /// + public override void ExecuteIn(Environment environment) + { + try + { + environment.GlobalEnvironment.Import(environment, Library.Interpolate(environment)); + } + catch (ImportException) + { + throw new InterpreterException(Coordinate, $"Cannot import library {Library.Interpolate(environment)} as it does not exist"); + } + catch (Exception e) + { + throw new InterpolationException(Coordinate, e.Message); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/Import.cs.meta b/Runtime/SassyPatching/Nodes/Statements/TopLevel/Import.cs.meta new file mode 100644 index 0000000..08e631c --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/Import.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: d421b49ab2e2f8f47a865cf1f0fdb1dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/Mixin.cs b/Runtime/SassyPatching/Nodes/Statements/TopLevel/Mixin.cs new file mode 100644 index 0000000..4ce4329 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/Mixin.cs @@ -0,0 +1,37 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel +{ + /// + /// Represents a selection block mixin + /// + public class Mixin : Node + { + /// + /// The name of the mixin + /// + public readonly string Name; + /// + /// The arguments that the mixin takes + /// + public readonly List Arguments; + /// + /// The list of nodes to be "mixed in" when included + /// + public readonly List Body; + internal Mixin(Coordinate c, string name, List arguments, List body) : base(c) + { + Name = name; + Arguments = arguments; + Body = body; + } + + /// + public override void ExecuteIn(Environment environment) + { + environment.GlobalEnvironment.AllMixins[Name] = new PatchMixin(this); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/Mixin.cs.meta b/Runtime/SassyPatching/Nodes/Statements/TopLevel/Mixin.cs.meta new file mode 100644 index 0000000..e36c94d --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/Mixin.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f1e32a2e2dbd45c478c34b839bf8f3d1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/PatchDeclaration.cs b/Runtime/SassyPatching/Nodes/Statements/TopLevel/PatchDeclaration.cs new file mode 100644 index 0000000..96ca3cf --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/PatchDeclaration.cs @@ -0,0 +1,26 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Utility; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel +{ + /// + /// Represents a declaration of which labels to patch + /// + public class PatchDeclaration : Node + { + /// + /// The labels to patch + /// + public List Labels; + + internal PatchDeclaration(Coordinate c, List labels) : base(c) => Labels = labels; + + /// + public override void ExecuteIn(Environment environment) + { + environment.GlobalEnvironment.Universe.PatchLabels(Labels.Select(label => label.Interpolate(environment)).ToArray()); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/PatchDeclaration.cs.meta b/Runtime/SassyPatching/Nodes/Statements/TopLevel/PatchDeclaration.cs.meta new file mode 100644 index 0000000..57aa06f --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/PatchDeclaration.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3032e1a905110f649907f479cfbf9e20 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinition.cs b/Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinition.cs new file mode 100644 index 0000000..2143111 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinition.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Utility; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel +{ + public class StageDefinition : Node + { + + public string Name; + public bool Implicit; + public bool Global; + public List Before; + public List After; + public StageDefinition(Coordinate c, string name) : base(c) + { + Name = name; + Implicit = true; + Global = false; + Before = new(); + After = new(); + } + + public StageDefinition(Coordinate c, string name, bool global) : base(c) + { + Name = name; + Global = global; + Implicit = !global; + Before = new(); + After = new(); + } + + public StageDefinition(Coordinate c, string name, List attributes) : base(c) + { + Name = name; + Global = false; + Implicit = false; + Before = new(); + After = new(); + foreach (var attribute in attributes) + { + if (attribute.After) + After.Add(attribute.Relative); + else + Before.Add(attribute.Relative); + } + } + + public override void ExecuteIn(Environment environment) + { + var universe = environment.GlobalEnvironment.Universe; + var id = environment.GlobalEnvironment.ModGuid; + var interpName = ""; + try + { + interpName = Name.Interpolate(environment); + } + catch (Exception e) + { + throw new InterpolationException(Coordinate, e.Message); + } + var name = $"{id}:{interpName}"; + var stage = new Stage(); + if (Global) // @global + { + stage.RunsAfter.Add(universe.LastImplicitGlobal); + universe.LastImplicitGlobal = name; + } else if (Implicit) // implicit + { + stage.RunsAfter.Add(universe.LastImplicitWithinMod[id]); + var post = universe.UnsortedStages[$"{id}:post"]; + post.RunsAfter.Clear(); + post.RunsAfter.Add(name); + universe.LastImplicitWithinMod[id] = name; + } + else // defined relations + { + stage.RunsAfter.AddRange(After.Select(x => + { + var interp = ""; + try + { + interp = x.Interpolate(environment); + } + catch (Exception e) + { + throw new InterpolationException(Coordinate, e.Message); + } + return (interp.Contains(":") || universe.AllMods.Contains(interp)) ? interp : $"{id}:{interp}"; + })); + stage.RunsBefore.AddRange(Before.Select(x => + { + var interp = ""; + try + { + interp = x.Interpolate(environment); + } + catch (Exception e) + { + throw new InterpolationException(Coordinate, e.Message); + } + return (interp.Contains(":") || universe.AllMods.Contains(interp)) ? interp : $"{id}:{interp}"; + })); + } + universe.UnsortedStages[name] = stage; + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinition.cs.meta b/Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinition.cs.meta new file mode 100644 index 0000000..54b9b17 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinition.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: feb1f04ef71fc674ebd5d81160e9be5f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinitionAttribute.cs b/Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinitionAttribute.cs new file mode 100644 index 0000000..37e9184 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinitionAttribute.cs @@ -0,0 +1,18 @@ +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel +{ + public class StageDefinitionAttribute : Node + { + public string Relative; + public bool After; + public StageDefinitionAttribute(Coordinate c, string relative, bool after) : base(c) + { + Relative = relative; + After = after; + } + public override void ExecuteIn(Environment environment) + { + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinitionAttribute.cs.meta b/Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinitionAttribute.cs.meta new file mode 100644 index 0000000..274a954 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/TopLevel/StageDefinitionAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f26539c00ca87094cabcebd1d4d7f6bf +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/VariableDeclaration.cs b/Runtime/SassyPatching/Nodes/Statements/VariableDeclaration.cs new file mode 100644 index 0000000..b80076b --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/VariableDeclaration.cs @@ -0,0 +1,167 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using PatchManager.SassyPatching.Exceptions; +using PatchManager.SassyPatching.Nodes.Expressions; +using PatchManager.SassyPatching.Nodes.Indexers; +using UniLinq; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements +{ + /// + /// Represents a variable declaration + /// + public class VariableDeclaration : Node + { + /// + /// The name of the variable being declared + /// + public readonly string Variable; + + /// + /// The list of indexers for list creation/indexing + /// + public readonly List Indexers; + + /// + /// The value being assigned to the variable + /// + public readonly Expression Value; + + + internal VariableDeclaration(Coordinate c, string variable, List indexers, Expression value) : base(c) + { + Variable = variable; + Indexers = indexers; + Value = value; + } + + /// + public override void ExecuteIn(Environment environment) + { + var subEnv = new Environment(environment.GlobalEnvironment, environment); + var current = DataValue.Null; + try + { + current = environment[Variable]; + } + catch + { + // Ignored + } + + var result = ComputeValues(subEnv, current); + environment[Variable] = result; + } + + private DataValue ComputeValues(Environment subEnv, DataValue current, int layer = 0) + { + if (Indexers.Count == layer) + { + subEnv["value"] = current; + return Value.Compute(subEnv); + } + + var indexer = Indexers[layer]; + switch (indexer) + { + case SingleIndexer singleIndexer: + { + var index = singleIndexer.Index.Compute(subEnv); + if (index.IsInteger) + { + return ComputeIntegerIndex(subEnv, current, layer, index, indexer); + } + + if (index.IsString) + { + return ComputeStringIndex(subEnv, current, layer, index, indexer); + } + + throw new InterpreterException(indexer.Coordinate, + $"Invalid index type {index.Type}, expected Integer or String"); + } + case EverythingIndexer everythingIndexer: + return current.Type switch + { + DataValue.DataType.List => current.List.Select(value => ComputeValues(subEnv, value, layer + 1)) + .ToList(), + DataValue.DataType.Dictionary => current.Dictionary + .Select(kv => (kv.Key, ComputeValues(subEnv, kv.Value, layer + 1))) + .ToDictionary(kv => kv.Key, kv => kv.Item2), + DataValue.DataType.None => DataValue.Null, + _ => throw new InterpreterException(everythingIndexer.Coordinate, + $"Attempting to use a `*` indexer on a value of type {current.Type}") + }; + default: + throw new InterpreterException(indexer.Coordinate, $"Unknown indexer type: {indexer.GetType()}"); + } + } + + private DataValue ComputeStringIndex( + Environment subEnv, + DataValue current, + int layer, + DataValue index, + Node indexer + ) + { + // ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault + return current.Type switch + { + DataValue.DataType.None => new Dictionary + { + [index.String] = ComputeValues(subEnv, DataValue.Null, layer + 1) + }, + DataValue.DataType.Dictionary => new Dictionary(current.Dictionary) + { + [index.String] = ComputeValues(subEnv, + current.Dictionary.TryGetValue(index.String, out var currentValue) + ? currentValue + : DataValue.Null, layer + 1), + }, + _ => throw new InterpreterException(indexer.Coordinate, + $"Attempting to index into a value of type {current.Type} with an indexer that is a String") + }; + } + + private DataValue ComputeIntegerIndex( + Environment subEnv, + DataValue current, + int layer, + DataValue index, + Node indexer + ) + { + // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault + switch (current.Type) + { + case DataValue.DataType.None: + { + var list = new List(); + for (var i = 0; i < index.Integer; i++) + { + list.Add(DataValue.Null); + } + + list.Add(ComputeValues(subEnv, DataValue.Null, layer + 1)); + return list; + } + case DataValue.DataType.List: + { + var list = new List(current.List); + while (list.Count <= (int)index.Integer) + { + list.Add(DataValue.Null); + } + + list[(int)index.Integer] = ComputeValues(subEnv, list[(int)index.Integer], layer + 1); + return list; + } + default: + throw new InterpreterException(indexer.Coordinate, + $"Attempting to index into a value of type {current.Type} with an indexer that is an Integer"); + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/VariableDeclaration.cs.meta b/Runtime/SassyPatching/Nodes/Statements/VariableDeclaration.cs.meta new file mode 100644 index 0000000..e54d9b0 --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/VariableDeclaration.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f61ed0094b22ac640a2cccd76b40d6db +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Nodes/Statements/While.cs b/Runtime/SassyPatching/Nodes/Statements/While.cs new file mode 100644 index 0000000..0746a2b --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/While.cs @@ -0,0 +1,58 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Nodes.Expressions; +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Nodes.Statements +{ + /// + /// Represents a loop that iterates while a condition remains true + /// + public class While : Node, ISelectionAction + { + /// + /// The condition to test + /// + public readonly Expression Condition; + /// + /// The body to iterate + /// + public readonly List Children; + internal While(Coordinate c, Expression condition, List children) : base(c) + { + Condition = condition; + Children = children; + } + + /// + public override void ExecuteIn(Environment environment) + { + while (Condition.Compute(environment).Truthy) + { + foreach (var child in Children) + { + child.ExecuteIn(environment); + } + } + } + + public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) + { + while (Condition.Compute(environment).Truthy) + { + foreach (var child in Children) + { + if (child is ISelectionAction selectionAction) + { + selectionAction.ExecuteOn(environment,selectable,modifiable); + } + else + { + child.ExecuteIn(environment); + } + } + } + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Nodes/Statements/While.cs.meta b/Runtime/SassyPatching/Nodes/Statements/While.cs.meta new file mode 100644 index 0000000..7b7c54f --- /dev/null +++ b/Runtime/SassyPatching/Nodes/Statements/While.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 824fea88dfe9dac40a1b15f28fd52e86 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/SassyPatchGrammar.meta b/Runtime/SassyPatching/SassyPatchGrammar.meta new file mode 100644 index 0000000..afc7a4b --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ed90a325df02e68489efd5e3efbc986e +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/SassyPatchGrammar/gen.meta b/Runtime/SassyPatching/SassyPatchGrammar/gen.meta new file mode 100644 index 0000000..2b795fe --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/gen.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 67a52bc687581ee46b77a7fcd32fa4b9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/gen/sassy_lexer.interp b/Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.interp similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/gen/sassy_lexer.interp rename to Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.interp diff --git a/Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.interp.meta b/Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.interp.meta new file mode 100644 index 0000000..5fc978a --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.interp.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7b2eb4ee256ec7c4c9d0a233a4d0bf5b +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/gen/sassy_lexer.java b/Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.java similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/gen/sassy_lexer.java rename to Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.java diff --git a/Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.java.meta b/Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.java.meta new file mode 100644 index 0000000..af66ceb --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.java.meta @@ -0,0 +1,32 @@ +fileFormatVersion: 2 +guid: d44accfe7d12df0428df863e988c23f4 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Android: Android + second: + enabled: 1 + settings: {} + - first: + Any: + second: + enabled: 0 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/gen/sassy_lexer.tokens b/Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.tokens similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/gen/sassy_lexer.tokens rename to Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.tokens diff --git a/Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.tokens.meta b/Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.tokens.meta new file mode 100644 index 0000000..0d97f45 --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/gen/sassy_lexer.tokens.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c940cb4b5fec4204781f7b3b3c68621c +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_lexer.cs b/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.cs similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_lexer.cs rename to Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.cs diff --git a/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.cs.meta b/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.cs.meta new file mode 100644 index 0000000..594ee11 --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 44bcbeca6da415d4a9b9f12a06e957f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_lexer.g4 b/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.g4 similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_lexer.g4 rename to Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.g4 diff --git a/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.g4.meta b/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.g4.meta new file mode 100644 index 0000000..157e741 --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.g4.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 7c1ba80e4d16db94e8dc07f4b9d59848 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_lexer.interp b/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.interp similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_lexer.interp rename to Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.interp diff --git a/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.interp.meta b/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.interp.meta new file mode 100644 index 0000000..eb79eb0 --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.interp.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: fb7d25d73be17ea4785c6b1d7d0dfda2 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_lexer.tokens b/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.tokens similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_lexer.tokens rename to Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.tokens diff --git a/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.tokens.meta b/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.tokens.meta new file mode 100644 index 0000000..21105e8 --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/sassy_lexer.tokens.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 020582f4fe0f20f428b8c70ed45da720 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parser.cs b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.cs similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parser.cs rename to Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.cs diff --git a/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.cs.meta b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.cs.meta new file mode 100644 index 0000000..0a2f0f6 --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ac417a7607ce5c948948e2fb8112bb57 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parser.g4 b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.g4 similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parser.g4 rename to Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.g4 diff --git a/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.g4.meta b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.g4.meta new file mode 100644 index 0000000..87dd885 --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.g4.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4910eb54bab2ce8459a9f47d8982c757 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parser.interp b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.interp similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parser.interp rename to Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.interp diff --git a/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.interp.meta b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.interp.meta new file mode 100644 index 0000000..c286226 --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.interp.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a26a66752105bdb4693f125f73c95504 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parser.tokens b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.tokens similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parser.tokens rename to Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.tokens diff --git a/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.tokens.meta b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.tokens.meta new file mode 100644 index 0000000..024dee9 --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parser.tokens.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: d3bcc21bc88644b478c86646a31b5147 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parserBaseListener.cs b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserBaseListener.cs similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parserBaseListener.cs rename to Runtime/SassyPatching/SassyPatchGrammar/sassy_parserBaseListener.cs diff --git a/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserBaseListener.cs.meta b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserBaseListener.cs.meta new file mode 100644 index 0000000..06698ef --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserBaseListener.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4c36f4c26cec32d439ebde8ae6f5781e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parserBaseVisitor.cs b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserBaseVisitor.cs similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parserBaseVisitor.cs rename to Runtime/SassyPatching/SassyPatchGrammar/sassy_parserBaseVisitor.cs diff --git a/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserBaseVisitor.cs.meta b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserBaseVisitor.cs.meta new file mode 100644 index 0000000..57cdde0 --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserBaseVisitor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f812711747db2e147a2ed1493c483a99 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parserListener.cs b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserListener.cs similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parserListener.cs rename to Runtime/SassyPatching/SassyPatchGrammar/sassy_parserListener.cs diff --git a/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserListener.cs.meta b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserListener.cs.meta new file mode 100644 index 0000000..616fef8 --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserListener.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c48ba68cf28f0fa469baefa1d4c68959 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parserVisitor.cs b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserVisitor.cs similarity index 100% rename from src/PatchManager.SassyPatching/SassyPatchGrammar/sassy_parserVisitor.cs rename to Runtime/SassyPatching/SassyPatchGrammar/sassy_parserVisitor.cs diff --git a/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserVisitor.cs.meta b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserVisitor.cs.meta new file mode 100644 index 0000000..fb0f051 --- /dev/null +++ b/Runtime/SassyPatching/SassyPatchGrammar/sassy_parserVisitor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6762dd5be40946b4b954bb7db1f1bf5d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Selectables.meta b/Runtime/SassyPatching/Selectables.meta new file mode 100644 index 0000000..3ba8d62 --- /dev/null +++ b/Runtime/SassyPatching/Selectables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 44a03e426e7cdda4a84da930123a5085 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Selectables/JTokenSelectable.cs b/Runtime/SassyPatching/Selectables/JTokenSelectable.cs new file mode 100644 index 0000000..5db6aee --- /dev/null +++ b/Runtime/SassyPatching/Selectables/JTokenSelectable.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Modifiables; + +namespace PatchManager.SassyPatching.Selectables +{ + /// + /// Represents a selectable that operates over objects + /// + public class JTokenSelectable : BaseSelectable + { + private readonly Action _markDirty; + /// + /// This is the token being modified + /// + protected readonly JToken Token; + + /// + /// Create a new JToken Selectable + /// + /// How this should notify that it has been modified + /// The token this operates over + /// The name/element this is coming from + /// The type of element this is, can be different from the name + public JTokenSelectable(Action markDirty, JToken token, string name, string? elementType = null) + { + _markDirty = markDirty; + Token = token; + ElementType = elementType ?? name; + _getName = _ => name; + Classes = new List(); + Children = new List(); + foreach (var subToken in token) + { + if (subToken is not JProperty property) continue; + Classes.Add(property.Name); + Children.Add(new JTokenSelectable(markDirty,property.Value,property.Name)); + } + } + + /// + /// Create a new JToken Selectable + /// + /// How this should notify that it has been modified + /// The token this operates over + /// The function used to get the name of this token + /// The type of element this is, can be different from the name + public JTokenSelectable(Action markDirty, JToken token, Func name, string? elementType = null) + { + _markDirty = markDirty; + Token = token; + ElementType = elementType ?? name(token); + _getName = name; + Classes = new(); + Children = new(); + foreach (var subToken in token) + { + if (subToken is not JProperty property) continue; + Classes.Add(property.Name); + Children.Add(new JTokenSelectable(markDirty,property.Value,property.Name)); + } + } + + /// + public sealed override List Children { get; } + + private readonly Func _getName; + + /// + public override string Name => _getName.Invoke(Token); + + /// + public sealed override List Classes { get; } + + public override bool MatchesClass(string @class, out DataValue classValue) + { + classValue = null; + if (!MatchesClass(@class)) + { + return false; + } + + classValue = DataValue.FromJToken(Token[@class]); + return true; + + } + + /// + public override string ElementType { get; } + + /// + public override bool IsSameAs(ISelectable other) => + other is JTokenSelectable jTokenSelectable && jTokenSelectable.Token == Token; + + /// + public override IModifiable OpenModification() + { + return new JTokenModifiable(Token,_markDirty); + } + + /// + public override ISelectable AddElement(string elementType) + { + var obj = new JObject(); + var token = Token; + while (token is JProperty prop) + token = prop.Value; + switch (token) + { + case JArray jArray: + jArray.Add(obj); + break; + case JObject jObject: + jObject[elementType] = obj; + break; + default: + throw new InvalidOperationException(); + } + var n = new JTokenSelectable(_markDirty, obj, elementType); + Children.Add(n); + return n; + } + + /// + public override string Serialize() => Token.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(Token); + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Selectables/JTokenSelectable.cs.meta b/Runtime/SassyPatching/Selectables/JTokenSelectable.cs.meta new file mode 100644 index 0000000..a2f8947 --- /dev/null +++ b/Runtime/SassyPatching/Selectables/JTokenSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2d6a2b3d4604b1c4083b1294a3a6bc74 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/SelectionUtilities.cs b/Runtime/SassyPatching/SelectionUtilities.cs new file mode 100644 index 0000000..87cabaf --- /dev/null +++ b/Runtime/SassyPatching/SelectionUtilities.cs @@ -0,0 +1,22 @@ +using System.Collections.Generic; +using PatchManager.SassyPatching.Execution; +using UniLinq; + +namespace PatchManager.SassyPatching +{ + internal static class SelectionUtilities + { + public static List CombineSelections(List a, List b) + { + var combination = a.ToList(); + combination.AddRange(b.Where(y => !combination.Any(x => x.Selectable.IsSameAs(y.Selectable)))); + return combination; + } + + public static List IntersectSelections(List a, List b) + { + return a.Where(x => b.Any(y => x.Selectable.IsSameAs(y.Selectable))).ToList(); + } + + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/SelectionUtilities.cs.meta b/Runtime/SassyPatching/SelectionUtilities.cs.meta new file mode 100644 index 0000000..f896438 --- /dev/null +++ b/Runtime/SassyPatching/SelectionUtilities.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 69f7a9a13aa301c4db92c98b978caa10 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Transformer.cs b/Runtime/SassyPatching/Transformer.cs new file mode 100644 index 0000000..1f391b2 --- /dev/null +++ b/Runtime/SassyPatching/Transformer.cs @@ -0,0 +1,824 @@ +using System; +using System.Globalization; +using PatchManager.SassyPatching.Nodes; +using PatchManager.SassyPatching.Nodes.Attributes; +using PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions; +using PatchManager.SassyPatching.Nodes.Expressions; +using PatchManager.SassyPatching.Nodes.Expressions.Binary; +using PatchManager.SassyPatching.Nodes.Expressions.Unary; +using PatchManager.SassyPatching.Nodes.Indexers; +using PatchManager.SassyPatching.Nodes.Selectors; +using PatchManager.SassyPatching.Nodes.Statements; +using PatchManager.SassyPatching.Nodes.Statements.FunctionLevel; +using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; +using PatchManager.SassyPatching.Nodes.Statements.TopLevel; +using PatchManager.SassyPatching.Utility; +using SassyPatchGrammar; +using UniLinq; +using UnityEngine; + +namespace PatchManager.SassyPatching +{ + /// + /// A class used for transforming an Antlr representation of a Patch to our own node tree representation + /// + public class Transformer : sassy_parserBaseVisitor + { + private readonly Action _logError; + + /// + /// Whether the transformation encountered an error + /// + public bool Errored; + + /// + /// Creates a new transformer + /// + /// The function called when an error is encountered + public Transformer(Action logError) + { + _logError = logError; + } + + private Node Error(Coordinate location, string error) + { + _logError($"{location.ToString()}: {error}"); + Errored = true; + return new ErrorNode(location, error); + } + + /// + public override Node VisitPatch(sassy_parser.PatchContext context) => + new SassyPatch(context.GetCoordinate(), + context.top_level_statement().Select(Visit) + .ToList()); + + /// + public override Node VisitPatch_declaration(sassy_parser.Patch_declarationContext context) + { + var labels = context.patch_list().sassy_string().Select(x => x.GetStringValue()).ToList(); + return new PatchDeclaration(context.GetCoordinate(), labels); + } + + /// + public override Node VisitImport_declaration(sassy_parser.Import_declarationContext context) => + new Import(context.GetCoordinate(), + context.imp.GetStringValue()); + + /// + public override Node VisitNormal_var_decl(sassy_parser.Normal_var_declContext context) + => new VariableDeclaration(context.GetCoordinate(), + context.variable.Text.TrimFirst(), + context.index().Select(Visit).Cast().ToList(), + Visit(context.val) as Expression); + + /// + public override Node VisitAdd_var_decl(sassy_parser.Add_var_declContext context) => new VariableDeclaration( + context.GetCoordinate(), + context.variable.Text.TrimFirst(), + context.index().Select(Visit).Cast().ToList(), + new ImplicitAdd(context.GetCoordinate(), Visit(context.val) as Expression)); + + /// + public override Node VisitSubtract_var_decl(sassy_parser.Subtract_var_declContext context) => + new VariableDeclaration( + context.GetCoordinate(), + context.variable.Text.TrimFirst(), + context.index().Select(Visit).Cast().ToList(), + new ImplicitSubtract(context.GetCoordinate(), Visit(context.val) as Expression)); + + /// + public override Node VisitMultiply_var_decl(sassy_parser.Multiply_var_declContext context) => + new VariableDeclaration( + context.GetCoordinate(), + context.variable.Text.TrimFirst(), + context.index().Select(Visit).Cast().ToList(), + new ImplicitMultiply(context.GetCoordinate(), Visit(context.val) as Expression)); + + /// + public override Node VisitDivide_var_decl(sassy_parser.Divide_var_declContext context) => new VariableDeclaration( + context.GetCoordinate(), + context.variable.Text.TrimFirst(), + context.index().Select(Visit).Cast().ToList(), + new ImplicitDivide(context.GetCoordinate(), Visit(context.val) as Expression)); + + /// + public override Node VisitFunction_def(sassy_parser.Function_defContext context) => + new Function(context.GetCoordinate(), + context.name.Text, + context.args.arg_decl() + .Select(Visit) + .Cast() + .ToList(), + context.body.function_statement().Select(Visit) + .ToList()); + + /// + public override Node VisitClosure(sassy_parser.ClosureContext context) => + new Closure(context.GetCoordinate(), + context.args.arg_decl() + .Select(Visit) + .Cast() + .ToList(), + context.body.function_statement().Select(Visit) + .ToList()); + + /// + public override Node VisitMixin_def(sassy_parser.Mixin_defContext context) => + new Mixin(context.GetCoordinate(), + context.name.Text, + context.args.arg_decl() + .Select(Visit) + .Cast() + .ToList(), + context.body.selector_statement().Select(Visit) + .ToList()); + + /// + public override Node VisitTop_level_conditional(sassy_parser.Top_level_conditionalContext context) + { + Node @else = null; + if (context.els != null) + { + @else = Visit(context.els); + } + + return new Conditional(context.GetCoordinate(), + Visit(context.cond) as Expression, + context.top_level_statement() + .Select(Visit) + .ToList(), + @else); + } + + /// + public override Node VisitTop_level_else_else(sassy_parser.Top_level_else_elseContext context) => + new Block(context.GetCoordinate(), + context.top_level_statement() + .Select(Visit) + .ToList()); + + /// + public override Node VisitTop_level_else_if(sassy_parser.Top_level_else_ifContext context) + { + Node @else = null; + if (context.els != null) + { + @else = Visit(context.els); + } + + return new Conditional(context.GetCoordinate(), + Visit(context.cond) as Expression, + context.top_level_statement() + .Select(Visit) + .ToList(), + @else); + } + + /// + public override Node VisitSelection_block(sassy_parser.Selection_blockContext context) => + new SelectionBlock(context.GetCoordinate(), + context.attributed_selector() + .attribute() + .Select(Visit) + .Cast() + .ToList(), + Visit(context.attributed_selector() + .selector()) as Selector, + context.selector_body() + .selector_statement().Select(Visit) + .ToList()); + + /// + public override Node VisitRequire_mod(sassy_parser.Require_modContext context) => + new RequireModAttribute(context.GetCoordinate(), Visit(context.expr) as RequireExpression); + + public override Node VisitRequire_not(sassy_parser.Require_notContext context) => + new RequireNot(context.GetCoordinate(), Visit(context.internal_expr) as RequireExpression); + + public override Node VisitRequire_and(sassy_parser.Require_andContext context) => + new RequireAnd(context.GetCoordinate(), Visit(context.lhs) as RequireExpression, + Visit(context.rhs) as RequireExpression); + + public override Node VisitRequire_or(sassy_parser.Require_orContext context) => + new RequireOr(context.GetCoordinate(), Visit(context.lhs) as RequireExpression, + Visit(context.rhs) as RequireExpression); + + public override Node VisitRequire_guid(sassy_parser.Require_guidContext context) => + new RequireGuid(context.GetCoordinate(), context.modid.GetStringValue()); + + /// + public override Node VisitRun_at_stage(sassy_parser.Run_at_stageContext context) => + new RunAtStageAttribute(context.GetCoordinate(), context.stage.GetStringValue()); + + public override Node VisitNew_asset(sassy_parser.New_assetContext context) + { + var expressions = context.constructor_arguments().expression().Select(Visit).Cast().ToList(); + return new NewAttribute(context.GetCoordinate(), expressions); + } + + /// + public override Node VisitSel_element(sassy_parser.Sel_elementContext context) + => new ElementSelector(context.GetCoordinate(), context.ELEMENT().GetText()); + + public override Node VisitSel_element_string(sassy_parser.Sel_element_stringContext context) => + new ElementSelector(context.GetCoordinate(), context.STRING().GetText().Unescape()); + + /// + public override Node VisitSel_ruleset(sassy_parser.Sel_rulesetContext context) + => new RulesetSelector(context.GetCoordinate(), context.RULESET().GetText().TrimFirst()); + + + /// + public override Node VisitSel_class_capture(sassy_parser.Sel_class_captureContext context) => + new ClassCaptureSelector(context.GetCoordinate(), context.CLASS().GetText().TrimFirst(), + context.function_statement().Select(Visit).ToList()); + + /// + public override Node VisitSel_string_class_capture(sassy_parser.Sel_string_class_captureContext context) => + new ClassCaptureSelector(context.GetCoordinate(), context.STRING_CLASS().GetText().TrimFirst().Unescape(), + context.function_statement().Select(Visit).ToList()); + + /// + public override Node VisitSel_child(sassy_parser.Sel_childContext context) + => new ChildSelector(context.GetCoordinate(), Visit(context.parent) as Selector, + Visit(context.child) as Selector); + + /// + public override Node VisitSel_add_element(sassy_parser.Sel_add_elementContext context) + => new ElementAdditionSelector(context.GetCoordinate(), context.ELEMENT().GetText()); + + /// + public override Node VisitSel_add_string_element(sassy_parser.Sel_add_string_elementContext context) + => new ElementAdditionSelector(context.GetCoordinate(), context.STRING().GetText().Unescape()); + + /// + public override Node VisitSel_class(sassy_parser.Sel_classContext context) + => new ClassSelector(context.GetCoordinate(), context.CLASS().GetText().TrimFirst()); + + /// + public override Node VisitSel_name(sassy_parser.Sel_nameContext context) + => new NameSelector(context.GetCoordinate(), context.NAME().GetText().TrimFirst()); + + /// + public override Node VisitSel_string_name(sassy_parser.Sel_string_nameContext context) => + new NameSelector(context.GetCoordinate(), context.STRING_NAME().GetText().TrimFirst().Unescape()); + + /// + public override Node VisitSel_intersection(sassy_parser.Sel_intersectionContext context) + => new IntersectionSelector(context.GetCoordinate(), Visit(context.lhs) as Selector, + Visit(context.rhs) as Selector); + + /// + public override Node VisitSel_ensure(sassy_parser.Sel_ensureContext context) => + new EnsureSelector(context.GetCoordinate(), context.ENSURE().GetText().TrimFirst()); + + /// + public override Node VisitSel_string_ensure(sassy_parser.Sel_string_ensureContext context) => + new EnsureSelector(context.GetCoordinate(), context.STRING_ENSURE().GetText().TrimFirst().Unescape()); + + /// + public override Node VisitSel_everything(sassy_parser.Sel_everythingContext context) + => new WildcardSelector(context.GetCoordinate()); + + /// + public override Node VisitSel_without_class(sassy_parser.Sel_without_classContext context) + => new WithoutClassSelector(context.GetCoordinate(), context.CLASS().GetText().TrimFirst()); + + /// + public override Node VisitSel_without_string_class(sassy_parser.Sel_without_string_classContext context) => + new WithoutClassSelector(context.GetCoordinate(), context.STRING_CLASS().GetText().TrimFirst().Unescape()); + + /// + public override Node VisitSel_without_name(sassy_parser.Sel_without_nameContext context) + => new WithoutNameSelector(context.GetCoordinate(), context.NAME().GetText().TrimFirst()); + + /// + public override Node VisitSel_without_string_name(sassy_parser.Sel_without_string_nameContext context) + => new WithoutNameSelector(context.GetCoordinate(), context.STRING_NAME().GetText().TrimFirst().Unescape()); + + /// + public override Node VisitSel_combination(sassy_parser.Sel_combinationContext context) + => new CombinationSelector(context.GetCoordinate(), Visit(context.lhs) as Selector, + Visit(context.rhs) as Selector); + + /// + public override Node VisitRuleset_selector(sassy_parser.Ruleset_selectorContext context) + => new RulesetSelector(context.GetCoordinate(), context.RULESET().GetText().TrimFirst()); + + /// + public override Node VisitCombination_selector(sassy_parser.Combination_selectorContext context) + => new CombinationSelector(context.GetCoordinate(), Visit(context.lhs) as Selector, + Visit(context.rhs) as Selector); + + /// + public override Node VisitClass_capture_selector(sassy_parser.Class_capture_selectorContext context) => + new ClassCaptureSelector(context.GetCoordinate(), context.CLASS().GetText().TrimFirst(), + context.function_statement().Select(Visit).ToList()); + + /// + public override Node VisitString_class_capture_selector( + sassy_parser.String_class_capture_selectorContext context + ) => + new ClassCaptureSelector(context.GetCoordinate(), context.STRING_CLASS().GetText().TrimFirst().Unescape(), + context.function_statement().Select(Visit).ToList()); + + /// + public override Node VisitWithout_name(sassy_parser.Without_nameContext context) + => new WithoutNameSelector(context.GetCoordinate(), context.NAME().GetText().TrimFirst()); + + /// + public override Node VisitWithout_string_name(sassy_parser.Without_string_nameContext context) => + new WithoutNameSelector(context.GetCoordinate(), context.STRING_NAME().GetText().TrimFirst().Unescape()); + + /// + public override Node VisitClass_selector(sassy_parser.Class_selectorContext context) + => new ClassSelector(context.GetCoordinate(), context.CLASS().GetText().TrimFirst()); + + /// + public override Node VisitString_class_selector(sassy_parser.String_class_selectorContext context) => + new ClassSelector(context.GetCoordinate(), context.STRING_CLASS().GetText().TrimFirst().Unescape()); + + /// + public override Node VisitWithout_class(sassy_parser.Without_classContext context) + => new WithoutClassSelector(context.GetCoordinate(), context.CLASS().GetText().TrimFirst()); + + /// + public override Node VisitWithout_string_class(sassy_parser.Without_string_classContext context) => + new WithoutClassSelector(context.GetCoordinate(), context.STRING_CLASS().GetText().TrimFirst().Unescape()); + + /// + public override Node VisitName(sassy_parser.NameContext context) + => new NameSelector(context.GetCoordinate(), context.NAME().GetText().TrimFirst()); + + /// + public override Node VisitString_name(sassy_parser.String_nameContext context) + => new NameSelector(context.GetCoordinate(), context.STRING_NAME().GetText().TrimFirst().Unescape()); + + /// + public override Node VisitAdd_element(sassy_parser.Add_elementContext context) + => new ElementAdditionSelector(context.GetCoordinate(), context.ELEMENT().GetText()); + + /// + public override Node VisitAdd_string_element(sassy_parser.Add_string_elementContext context) + => new ElementAdditionSelector(context.GetCoordinate(), context.STRING().GetText().Unescape()); + + /// + public override Node VisitEverything(sassy_parser.EverythingContext context) + => new WildcardSelector(context.GetCoordinate()); + + /// + public override Node VisitIntersection_selector(sassy_parser.Intersection_selectorContext context) + => new IntersectionSelector(context.GetCoordinate(), Visit(context.lhs) as Selector, + Visit(context.rhs) as Selector); + + /// + public override Node VisitElement(sassy_parser.ElementContext context) + => new ElementSelector(context.GetCoordinate(), context.ELEMENT().GetText()); + + /// + public override Node VisitString_element(sassy_parser.String_elementContext context) => + new ElementSelector(context.GetCoordinate(), context.STRING().GetText().Unescape()); + + /// + public override Node VisitSel_level_conditional(sassy_parser.Sel_level_conditionalContext context) + { + Node @else = null; + if (context.els != null) + { + @else = Visit(context.els); + } + + return new Conditional(context.GetCoordinate(), + Visit(context.cond) as Expression, + context.selector_statement() + .Select(Visit) + .ToList(), + @else); + } + + /// + public override Node VisitSel_level_else_else(sassy_parser.Sel_level_else_elseContext context) => + new Block(context.GetCoordinate(), + context.selector_statement() + .Select(Visit) + .ToList()); + + /// + public override Node VisitSel_level_else_if(sassy_parser.Sel_level_else_ifContext context) + { + Node @else = null; + if (context.els != null) + { + @else = Visit(context.els); + } + + return new Conditional(context.GetCoordinate(), + Visit(context.cond) as Expression, + context.selector_statement() + .Select(Visit) + .ToList(), + @else); + } + + /// + public override Node VisitSet_value(sassy_parser.Set_valueContext context) + => new SetValue(context.GetCoordinate(), Visit(context.expr) as Expression); + + /// + public override Node VisitDelete_value(sassy_parser.Delete_valueContext context) + => new DeleteValue(context.GetCoordinate()); + + /// + public override Node VisitMerge_value(sassy_parser.Merge_valueContext context) + => new MergeValue(context.GetCoordinate(), Visit(context.expr) as Expression); + + /// + public override Node VisitNormal_field_set(sassy_parser.Normal_field_setContext context) => + new Field(context.GetCoordinate(), + context.sassy_string().GetStringValue(), + context.index().Select(Visit).Cast().ToList(), + Visit(context.expr) as Expression); + + /// + public override Node VisitAdd_field_set(sassy_parser.Add_field_setContext context) => + new Field(context.GetCoordinate(), + context.sassy_string().GetStringValue(), + context.index().Select(Visit).Cast().ToList(), + new ImplicitAdd(context.GetCoordinate(), Visit(context.expr) as Expression)); + + /// + public override Node VisitSubtract_field_set(sassy_parser.Subtract_field_setContext context) => + new Field(context.GetCoordinate(), + context.sassy_string().GetStringValue(), + context.index().Select(Visit).Cast().ToList(), + new ImplicitSubtract(context.GetCoordinate(), Visit(context.expr) as Expression)); + + /// + public override Node VisitMultiply_field_set(sassy_parser.Multiply_field_setContext context) => + new Field(context.GetCoordinate(), + context.sassy_string().GetStringValue(), + context.index().Select(Visit).Cast().ToList(), + new ImplicitMultiply(context.GetCoordinate(), Visit(context.expr) as Expression)); + + + /// + public override Node VisitDivide_field_set(sassy_parser.Divide_field_setContext context) => + new Field(context.GetCoordinate(), + context.sassy_string().GetStringValue(), + context.index().Select(Visit).Cast().ToList(), + new ImplicitDivide(context.GetCoordinate(), Visit(context.expr) as Expression)); + + + public override Node VisitExpression_indexer(sassy_parser.Expression_indexerContext context) => new SingleIndexer(context.GetCoordinate(),Visit(context.expression()) as Expression); + + public override Node VisitMap_indexer(sassy_parser.Map_indexerContext context) => new EverythingIndexer(context.GetCoordinate()); + + + /// + public override Node VisitNot_equal_to(sassy_parser.Not_equal_toContext context) => + new NotEqualTo(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); + + /// + public override Node VisitVariable_reference(sassy_parser.Variable_referenceContext context) => + new VariableReference(context.GetCoordinate(), context.VARIABLE().GetText().TrimFirst()); + + /// + public override Node VisitEqual_to(sassy_parser.Equal_toContext context) => + new EqualTo(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); + + /// + public override Node VisitLocal_variable_reference(sassy_parser.Local_variable_referenceContext context) => + new LocalVariableReference(context.GetCoordinate(), context.LOCALVARIABLE().GetText().TrimFirst().TrimFirst()); + + + /// + public override Node VisitIndexor(sassy_parser.IndexorContext context) => + new Subscript(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); + + /// + public override Node VisitOr(sassy_parser.OrContext context) => + new Or(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); + + /// + public override Node VisitLesser_than_equal(sassy_parser.Lesser_than_equalContext context) => + new LesserThanEqual(context.GetCoordinate(), Visit(context.lhs) as Expression, + Visit(context.rhs) as Expression); + + /// + public override Node VisitSubtraction(sassy_parser.SubtractionContext context) => + new Subtract(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); + + /// + public override Node VisitPositive(sassy_parser.PositiveContext context) => + new Positive(context.GetCoordinate(), Visit(context.child) as Expression); + + /// + public override Node VisitSimple_call(sassy_parser.Simple_callContext context) => + new SimpleCall(context.GetCoordinate(), context.lhs.Text, + context.args.argument().Select(Visit).Cast().ToList()); + + /// + public override Node VisitDivision(sassy_parser.DivisionContext context) => + new Divide(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); + + /// + public override Node VisitNegative(sassy_parser.NegativeContext context) => + new Negate(context.GetCoordinate(), Visit(context.child) as Expression); + + /// + public override Node VisitNot(sassy_parser.NotContext context) => + new Not(context.GetCoordinate(), Visit(context.child) as Expression); + + /// + public override Node VisitLesser_than(sassy_parser.Lesser_thanContext context) => + new LesserThan(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); + + /// + public override Node VisitMember_call(sassy_parser.Member_callContext context) => + new MemberCall(context.GetCoordinate(), Visit(context.lhs) as Expression, context.name.Text, + context.args.argument().Select(Visit).Cast().ToList()); + + /// + public override Node VisitMember_call_ruleset(sassy_parser.Member_call_rulesetContext context) => + new MemberCall(context.GetCoordinate(), Visit(context.lhs) as Expression, + context.RULESET().GetText().TrimFirst(), + context.args.argument().Select(Visit).Cast().ToList()); + + /// + public override Node VisitGreater_than(sassy_parser.Greater_thanContext context) => + new GreaterThan(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); + + /// + public override Node VisitAnd(sassy_parser.AndContext context) => + new And(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); + + /// + public override Node VisitMultiplication(sassy_parser.MultiplicationContext context) => + new Multiply(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); + + /// + public override Node VisitRemainder(sassy_parser.RemainderContext context) => + new Remainder(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); + + /// + public override Node VisitGreater_than_equal(sassy_parser.Greater_than_equalContext context) => + new GreaterThanEqual(context.GetCoordinate(), Visit(context.lhs) as Expression, + Visit(context.rhs) as Expression); + + /// + public override Node VisitTernary(sassy_parser.TernaryContext context) => + new Ternary(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.cond) as Expression, + Visit(context.rhs) as Expression); + + /// + public override Node VisitAddition(sassy_parser.AdditionContext context) => + new Add(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); + + /// + public override Node VisitValue_deletion(sassy_parser.Value_deletionContext context) + => new ValueNode(context.GetCoordinate(), new DataValue(DataValue.DataType.Deletion)); + + /// + public override Node VisitBoolean_true(sassy_parser.Boolean_trueContext context) + => new ValueNode(context.GetCoordinate(), true); + + /// + public override Node VisitBoolean_false(sassy_parser.Boolean_falseContext context) + => new ValueNode(context.GetCoordinate(), false); + + /// + public override Node VisitNumber_value(sassy_parser.Number_valueContext context) + { + var location = context.GetCoordinate(); + if (long.TryParse(context.NUMBER().GetText(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var lng)) + { + return new ValueNode(location, lng); + } + + if (double.TryParse(context.NUMBER().GetText(), NumberStyles.Number, CultureInfo.InvariantCulture, out var dbl)) + { + return new ValueNode(location, dbl); + } + + Debug.Log($"Number: {context.NUMBER().GetText()}"); + return Error(location, "Numbers must be parsable as a double precision floating point number"); + } + + /// + public override Node VisitString_value(sassy_parser.String_valueContext context) + => new ValueNode(context.GetCoordinate(), context.STRING().GetText().Unescape()); + + /// + public override Node VisitNone(sassy_parser.NoneContext context) + => new ValueNode(context.GetCoordinate(), new DataValue(DataValue.DataType.None)); + + /// + public override Node VisitList_value(sassy_parser.List_valueContext context) + => new ListNode(context.GetCoordinate(), + context.list().list_values().expression().Select(Visit).Cast().ToList()); + + /// + public override Node VisitObject_value(sassy_parser.Object_valueContext context) + => new ObjectNode(context.GetCoordinate(), + context.obj().obj_values().key_value().Select(Visit).Cast().ToList()); + + /// + public override Node VisitLiteral_key(sassy_parser.Literal_keyContext context) + => new KeyValueNode(context.GetCoordinate(), context.key.Text, Visit(context.val) as Expression); + + /// + public override Node VisitString_key(sassy_parser.String_keyContext context) + => new KeyValueNode(context.GetCoordinate(), context.key.Text.Unescape(), Visit(context.val) as Expression); + + /// + public override Node VisitNamed_argument(sassy_parser.Named_argumentContext context) + => new CallArgument(context.GetCoordinate(), context.key.Text.TrimFirst(), Visit(context.val) as Expression); + + /// + public override Node VisitUnnamed_argument(sassy_parser.Unnamed_argumentContext context) + => new CallArgument(context.GetCoordinate(), Visit(context.val) as Expression); + + /// + public override Node VisitFn_level_conditional(sassy_parser.Fn_level_conditionalContext context) + { + Node @else = null; + if (context.els != null) + { + @else = Visit(context.els); + } + + return new Conditional(context.GetCoordinate(), + Visit(context.cond) as Expression, + context.function_statement() + .Select(Visit) + .ToList(), + @else); + } + + /// + public override Node VisitFn_level_else_else(sassy_parser.Fn_level_else_elseContext context) => + new Block(context.GetCoordinate(), + context.function_statement() + .Select(Visit) + .ToList()); + + /// + public override Node VisitFn_level_else_if(sassy_parser.Fn_level_else_ifContext context) + { + Node @else = null; + if (context.els != null) + { + @else = Visit(context.els); + } + + return new Conditional(context.GetCoordinate(), + Visit(context.cond) as Expression, + context.function_statement() + .Select(Visit) + .ToList(), + @else); + } + + /// + public override Node VisitFn_return(sassy_parser.Fn_returnContext context) + { + return new Return(context.GetCoordinate(), Visit(context.expression()) as Expression); + } + + /// + public override Node VisitMixin_include(sassy_parser.Mixin_includeContext context) => + new MixinInclude(context.GetCoordinate(), context.mixin.Text, + context.args.argument().Select(Visit).Cast().ToList()); + + + /// + public override Node VisitMixin_block_include(sassy_parser.Mixin_block_includeContext context) => + new MixinBlockInclude(context.GetCoordinate(), context.mixin.Text, + context.args.argument().Select(Visit).Cast().ToList(), + context.selector_statement().Select(Visit).ToList()); + + public override Node VisitMixin_slot(sassy_parser.Mixin_slotContext context) => + new MixinSlot(context.GetCoordinate()); + + /// + public override Node VisitArgument_without_default(sassy_parser.Argument_without_defaultContext context) + => new Argument(context.GetCoordinate(), context.name.Text.TrimFirst()); + + /// + public override Node VisitArgument_with_default(sassy_parser.Argument_with_defaultContext context) + => new Argument(context.GetCoordinate(), context.name.Text.TrimFirst(), Visit(context.val) as Expression); + + /// + public override Node VisitSel_sub(sassy_parser.Sel_subContext context) => + Visit(context.internal_selector); + + /// + public override Node VisitSub_selector(sassy_parser.Sub_selectorContext context) => + Visit(context.internal_selector); + + /// + public override Node VisitSub_sub_expression(sassy_parser.Sub_sub_expressionContext context) => + Visit(context.internal_expr); + + /// + public override Node VisitFor_to_loop(sassy_parser.For_to_loopContext context) + => new For(context.GetCoordinate(), context.idx.Text.TrimFirst(), Visit(context.for_start) as Expression, false, + Visit(context.end) as Expression, context.function_statement().Select(Visit).ToList()); + + /// + public override Node VisitTop_level_for_to_loop(sassy_parser.Top_level_for_to_loopContext context) => new For( + context.GetCoordinate(), context.idx.Text.TrimFirst(), Visit(context.for_start) as Expression, false, + Visit(context.end) as Expression, context.top_level_statement().Select(Visit).ToList()); + + /// + public override Node VisitSel_level_for_to_loop(sassy_parser.Sel_level_for_to_loopContext context) => new For( + context.GetCoordinate(), context.idx.Text.TrimFirst(), Visit(context.for_start) as Expression, false, + Visit(context.end) as Expression, context.selector_statement().Select(Visit).ToList()); + + /// + public override Node VisitFor_through_loop(sassy_parser.For_through_loopContext context) + => new For(context.GetCoordinate(), context.idx.Text.TrimFirst(), Visit(context.for_start) as Expression, true, + Visit(context.end) as Expression, context.function_statement().Select(Visit).ToList()); + + + /// + public override Node VisitTop_level_for_through_loop(sassy_parser.Top_level_for_through_loopContext context) + => new For(context.GetCoordinate(), context.idx.Text.TrimFirst(), Visit(context.for_start) as Expression, true, + Visit(context.end) as Expression, context.top_level_statement().Select(Visit).ToList()); + + /// + public override Node VisitSel_level_for_through_loop(sassy_parser.Sel_level_for_through_loopContext context) + => new For(context.GetCoordinate(), context.idx.Text.TrimFirst(), Visit(context.for_start) as Expression, true, + Visit(context.end) as Expression, context.selector_statement().Select(Visit).ToList()); + + /// + public override Node VisitEach_loop(sassy_parser.Each_loopContext context) + => new Each(context.GetCoordinate(), context.key?.Text.TrimFirst(), context.val.Text.TrimFirst(), + Visit(context.iter) as Expression, context.function_statement().Select(Visit).ToList()); + + /// + public override Node VisitTop_level_each_loop(sassy_parser.Top_level_each_loopContext context) + => new Each(context.GetCoordinate(), context.key?.Text.TrimFirst(), context.val.Text.TrimFirst(), + Visit(context.iter) as Expression, context.top_level_statement().Select(Visit).ToList()); + + /// + public override Node VisitSel_level_each_loop(sassy_parser.Sel_level_each_loopContext context) + => new Each(context.GetCoordinate(), context.key?.Text.TrimFirst(), context.val.Text.TrimFirst(), + Visit(context.iter) as Expression, context.selector_statement().Select(Visit).ToList()); + + /// + public override Node VisitWhile_loop(sassy_parser.While_loopContext context) + => new While(context.GetCoordinate(), Visit(context.cond) as Expression, + context.function_statement().Select(Visit).ToList()); + + /// + public override Node VisitTop_level_while_loop(sassy_parser.Top_level_while_loopContext context) + => new While(context.GetCoordinate(), Visit(context.cond) as Expression, + context.top_level_statement().Select(Visit).ToList()); + + /// + public override Node VisitSel_level_while_loop(sassy_parser.Sel_level_while_loopContext context) + => new While(context.GetCoordinate(), Visit(context.cond) as Expression, + context.selector_statement().Select(Visit).ToList()); + + /// + public override Node VisitGlobal_stage_def(sassy_parser.Global_stage_defContext context) => + new StageDefinition(context.GetCoordinate(), context.stage.GetStringValue(), true); + + /// + public override Node VisitImplicit_stage_def(sassy_parser.Implicit_stage_defContext context) => + new StageDefinition(context.GetCoordinate(), context.stage.GetStringValue()); + + /// + public override Node VisitRelative_stage_def(sassy_parser.Relative_stage_defContext context) => new StageDefinition( + context.GetCoordinate(), context.stage.GetStringValue(), + context.stage_attribute().Select(Visit).Cast().ToList()); + + public override Node VisitStage_value_before(sassy_parser.Stage_value_beforeContext context) => + new StageDefinitionAttribute(context.GetCoordinate(), context.stage.GetStringValue(), false); + + public override Node VisitStage_value_after(sassy_parser.Stage_value_afterContext context) => + new StageDefinitionAttribute(context.GetCoordinate(), context.stage.GetStringValue(), true); + + /// + public override Node VisitConfig_creation(sassy_parser.Config_creationContext context) => new ConfigCreation( + context.GetCoordinate(), context.label.GetStringValue(), context.config_name.GetStringValue(), + Visit(context.config_value) as Expression); + + /// + public override Node VisitElement_string(sassy_parser.Element_stringContext context) => + new ValueNode(context.GetCoordinate(), context.ELEMENT().GetText()); + + /// + public override Node VisitUpdate_config_full(sassy_parser.Update_config_fullContext context) => new ConfigUpdate( + context.GetCoordinate(), Visit(context.priority) as Expression, context.label.GetStringValue(), + context.config_name.GetStringValue(), Visit(context.config_update) as Expression); + + /// + public override Node VisitUpdate_config_label(sassy_parser.Update_config_labelContext context) => new ConfigUpdate( + context.GetCoordinate(), Visit(context.priority) as Expression, context.label.GetStringValue(), null, + Visit(context.config_update) as Expression); + + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Transformer.cs.meta b/Runtime/SassyPatching/Transformer.cs.meta new file mode 100644 index 0000000..d5f4079 --- /dev/null +++ b/Runtime/SassyPatching/Transformer.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1aa22fdd2980ee341a2b3556069c1eca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Utility.meta b/Runtime/SassyPatching/Utility.meta new file mode 100644 index 0000000..e8849b0 --- /dev/null +++ b/Runtime/SassyPatching/Utility.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8addbe1e29df219418b85710fbfbcab0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/SassyPatching/Utility/Extensions.cs b/Runtime/SassyPatching/Utility/Extensions.cs new file mode 100644 index 0000000..6307151 --- /dev/null +++ b/Runtime/SassyPatching/Utility/Extensions.cs @@ -0,0 +1,131 @@ +using System; +using System.Text; +using System.Text.RegularExpressions; +using Antlr4.Runtime; +using Newtonsoft.Json; +using PatchManager.SassyPatching.Execution; +using PatchManager.SassyPatching.Nodes.Expressions; +using SassyPatchGrammar; +using UnityEngine; +using Environment = PatchManager.SassyPatching.Execution.Environment; + +namespace PatchManager.SassyPatching.Utility +{ + internal static class Extensions + { + public static string Unescape(this string @this) => Regex.Unescape(@this.Substring(1, @this.Length - 2)); + + public static string TrimFirst(this string @this) => @this.Substring(1); + + public static Coordinate GetCoordinate(this ParserRuleContext @this) => + new(@this.Start.TokenSource.SourceName, @this.Start.Line, @this.Start.Column); + + public static bool MatchesPattern(this string @this, string pattern) => + Regex.IsMatch(@this, $"^{pattern.Replace("*", ".*").Replace("?", ".?")}$"); + + public static string Escape(this string @this) => JsonConvert.ToString(@this); + + public static string GetStringValue(this sassy_parser.Sassy_stringContext ctx) + { + if (ctx is sassy_parser.Quoted_stringContext quotedStringContext) + { + return quotedStringContext.STRING().GetText().Unescape(); + } + + var unquotedStringContext = ctx as sassy_parser.Unquoted_stringContext; + return unquotedStringContext!.ELEMENT().GetText(); + } + + private static object GetResult(this string variable, Environment environment) + { + var lexer = new sassy_lexer(CharStreams.fromString(variable)); + var lexerErrorGenerator = new Universe.LexerListener("Interpolated string", + environment.GlobalEnvironment.Universe.MessageLogger); + lexer.AddErrorListener(lexerErrorGenerator); + if (lexerErrorGenerator.Errored) + { + throw new Exception("Lexer errors detected"); + } + + var tokenStream = new CommonTokenStream(lexer); + var parser = new sassy_parser(tokenStream); + var parserErrorGenerator = new Universe.ParserListener("Interpolated string", + environment.GlobalEnvironment.Universe.MessageLogger); + parser.AddErrorListener(parserErrorGenerator); + var expressionContext = parser.expression(); + if (parserErrorGenerator.Errored) + throw new Exception("parser errors detected"); + var tokenTransformer = new Transformer(msg => throw new Exception(msg)); + var ctx = tokenTransformer.Visit(expressionContext) as Expression; + var result = ctx!.Compute(environment); + return result.IsString ? result.String : result.ToString(); + } + + public static string Interpolate(this string toBeInterpolated, Environment environment) + { + if (toBeInterpolated.IndexOf("#", StringComparison.Ordinal) == -1) + return toBeInterpolated; + StringBuilder format = new(); + var inFormat = false; + var currentString = ""; + var lookForStart = false; + + foreach (var character in toBeInterpolated) + { + if (inFormat) + { + if (character is '}') + { + format.Append(currentString.GetResult(environment)); + inFormat = false; + } + else + { + currentString += character; + } + } + else + { + if (lookForStart) + { + switch (character) + { + case '{': + currentString = ""; + inFormat = true; + break; + case '#': + format.Append('#'); + break; + default: + format.Append('#'); + format.Append(character); + break; + } + + lookForStart = false; + } + else if (character == '#') + { + lookForStart = true; + } + else + { + format.Append(character); + } + } + } + + if (lookForStart) + { + format.Append('#'); + } + + if (inFormat) + { + throw new Exception("Unterminated interpolated string"); + } + return format.ToString(); + } + } +} \ No newline at end of file diff --git a/Runtime/SassyPatching/Utility/Extensions.cs.meta b/Runtime/SassyPatching/Utility/Extensions.cs.meta new file mode 100644 index 0000000..eb0187b --- /dev/null +++ b/Runtime/SassyPatching/Utility/Extensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 92c120305d9595146a5ca258a03c9ad1 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science.meta b/Runtime/Science.meta new file mode 100644 index 0000000..9c84806 --- /dev/null +++ b/Runtime/Science.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 23a2dae2f6134439a7740484bbbbd5f8 +timeCreated: 1739405245 \ No newline at end of file diff --git a/Runtime/Science/Modifiables.meta b/Runtime/Science/Modifiables.meta new file mode 100644 index 0000000..cd2c622 --- /dev/null +++ b/Runtime/Science/Modifiables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7f4cfb165f32f6a4aa77dd58875421ba +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Modifiables/DiscoverablesModifiable.cs b/Runtime/Science/Modifiables/DiscoverablesModifiable.cs new file mode 100644 index 0000000..6f6cfd6 --- /dev/null +++ b/Runtime/Science/Modifiables/DiscoverablesModifiable.cs @@ -0,0 +1,34 @@ +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Modifiables; +using PatchManager.Science.Selectables; + +namespace PatchManager.Science.Modifiables +{ + /// + /// Modifiable for . This is used to modify the discoverables object. + /// + public class DiscoverablesModifiable : JTokenModifiable + { + private DiscoverablesSelectable _discoverablesSelectable; + + /// + /// Creates a new for the given . + /// + /// The selectable to modify. + public DiscoverablesModifiable(DiscoverablesSelectable selectable) : base(selectable.DiscoverablesObject, selectable.SetModified) + { + _discoverablesSelectable = selectable; + } + + /// + public override void Set(DataValue dataValue) + { + if (dataValue.IsDeletion) + { + _discoverablesSelectable.SetDeleted(); + return; + } + base.Set(dataValue); + } + } +} \ No newline at end of file diff --git a/Runtime/Science/Modifiables/DiscoverablesModifiable.cs.meta b/Runtime/Science/Modifiables/DiscoverablesModifiable.cs.meta new file mode 100644 index 0000000..2315206 --- /dev/null +++ b/Runtime/Science/Modifiables/DiscoverablesModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5679a756be97d3e48bc55d2f15ecef51 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Modifiables/ExperimentModifiable.cs b/Runtime/Science/Modifiables/ExperimentModifiable.cs new file mode 100644 index 0000000..6cbbcef --- /dev/null +++ b/Runtime/Science/Modifiables/ExperimentModifiable.cs @@ -0,0 +1,37 @@ +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Modifiables; +using PatchManager.Science.Selectables; + +namespace PatchManager.Science.Modifiables +{ + /// + /// Modifiable for . + /// + public class ExperimentModifiable : JTokenModifiable + { + /// + /// The this modifiable is for. + /// + private ExperimentSelectable _experimentSelectable; + + /// + /// Creates a new for the given . + /// + /// The this modifiable is for. + public ExperimentModifiable(ExperimentSelectable selectable) : base(selectable.DataObject, selectable.SetModified) + { + _experimentSelectable = selectable; + } + + /// + public override void Set(DataValue dataValue) + { + if (dataValue.IsDeletion) + { + _experimentSelectable.SetDeleted(); + return; + } + base.Set(dataValue); + } + } +} \ No newline at end of file diff --git a/Runtime/Science/Modifiables/ExperimentModifiable.cs.meta b/Runtime/Science/Modifiables/ExperimentModifiable.cs.meta new file mode 100644 index 0000000..1d9414a --- /dev/null +++ b/Runtime/Science/Modifiables/ExperimentModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0d67e1f60c46013498479bda71d50d03 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Modifiables/RegionsModifiable.cs b/Runtime/Science/Modifiables/RegionsModifiable.cs new file mode 100644 index 0000000..a2949ff --- /dev/null +++ b/Runtime/Science/Modifiables/RegionsModifiable.cs @@ -0,0 +1,34 @@ +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Modifiables; +using PatchManager.Science.Selectables; + +namespace PatchManager.Science.Modifiables +{ + /// + /// Modifiable for . This is used to modify the discoverables object. + /// + public class RegionsModifiable : JTokenModifiable + { + private RegionsSelectable _regionsSelectable; + + /// + /// Creates a new for the given . + /// + /// The selectable to modify. + public RegionsModifiable(RegionsSelectable selectable) : base(selectable.RegionsObject, selectable.SetModified) + { + _regionsSelectable = selectable; + } + + /// + public override void Set(DataValue dataValue) + { + if (dataValue.IsDeletion) + { + _regionsSelectable.SetDeleted(); + return; + } + base.Set(dataValue); + } + } +} \ No newline at end of file diff --git a/Runtime/Science/Modifiables/RegionsModifiable.cs.meta b/Runtime/Science/Modifiables/RegionsModifiable.cs.meta new file mode 100644 index 0000000..84cc04d --- /dev/null +++ b/Runtime/Science/Modifiables/RegionsModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e35fa343799c3f24b9501e9cf548d389 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Modifiables/ScienceModifiable.cs b/Runtime/Science/Modifiables/ScienceModifiable.cs new file mode 100644 index 0000000..7329e63 --- /dev/null +++ b/Runtime/Science/Modifiables/ScienceModifiable.cs @@ -0,0 +1,34 @@ +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Modifiables; +using PatchManager.Science.Selectables; + +namespace PatchManager.Science.Modifiables +{ + /// + /// Modifiable for . This is used to modify the science object. + /// + public class ScienceModifiable : JTokenModifiable + { + private ScienceSelectable _scienceSelectable; + + /// + /// Creates a new for the given . + /// + /// The selectable to modify. + public ScienceModifiable(ScienceSelectable selectable) : base(selectable.ScienceObject, selectable.SetModified) + { + _scienceSelectable = selectable; + } + + /// + public override void Set(DataValue dataValue) + { + if (dataValue.IsDeletion) + { + _scienceSelectable.SetDeleted(); + return; + } + base.Set(dataValue); + } + } +} \ No newline at end of file diff --git a/Runtime/Science/Modifiables/ScienceModifiable.cs.meta b/Runtime/Science/Modifiables/ScienceModifiable.cs.meta new file mode 100644 index 0000000..1b8be50 --- /dev/null +++ b/Runtime/Science/Modifiables/ScienceModifiable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c076be515f316294ba87b1a27d6c8520 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Rulesets.meta b/Runtime/Science/Rulesets.meta new file mode 100644 index 0000000..b9aeed5 --- /dev/null +++ b/Runtime/Science/Rulesets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 932893411458238469d4bfff9a6f9fc5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Rulesets/DiscoverablesRuleset.cs b/Runtime/Science/Rulesets/DiscoverablesRuleset.cs new file mode 100644 index 0000000..05fdcd2 --- /dev/null +++ b/Runtime/Science/Rulesets/DiscoverablesRuleset.cs @@ -0,0 +1,41 @@ +using System; +using System.Collections.Generic; +using KSP.Game.Science; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; +using PatchManager.Science.Selectables; + +namespace PatchManager.Science.Rulesets +{ + /// + /// A ruleset for modifying discoverable positions in the game + /// + [PatcherRuleset("discoverables","science_region_discoverables")] + public class DiscoverablesRuleset : IPatcherRuleSet + { + /// + public bool Matches(string label) => label == "science_region_discoverables"; + + /// + public ISelectable ConvertToSelectable(string type, string name, string jsonData) => + new DiscoverablesSelectable(JObject.Parse(jsonData)); + + /// + public INewAsset CreateNew(List dataValues) + { + var bodyName = dataValues[0].String; + var bakedDiscoverables = new CelestialBodyBakedDiscoverables + { + BodyName = bodyName, + Discoverables = Array.Empty(), + Version = dataValues.Count > 1 ? dataValues[1].String : "0.1" + }; + return new NewGenericAsset("science_region_discoverables", + $"{bodyName.ToLowerInvariant()}_science_regions_discoverables", + new DiscoverablesSelectable(JObject.FromObject(bakedDiscoverables))); + } + } +} \ No newline at end of file diff --git a/Runtime/Science/Rulesets/DiscoverablesRuleset.cs.meta b/Runtime/Science/Rulesets/DiscoverablesRuleset.cs.meta new file mode 100644 index 0000000..e8d2175 --- /dev/null +++ b/Runtime/Science/Rulesets/DiscoverablesRuleset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eb1bcdbb47ded594799e4ede1a4de0dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Rulesets/ExperimentRuleset.cs b/Runtime/Science/Rulesets/ExperimentRuleset.cs new file mode 100644 index 0000000..2912394 --- /dev/null +++ b/Runtime/Science/Rulesets/ExperimentRuleset.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using JetBrains.Annotations; +using KSP.Game.Science; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; +using PatchManager.Science.Selectables; + +namespace PatchManager.Science.Rulesets +{ + /// + /// Ruleset for the ScienceExperiment part module. + /// + [PatcherRuleset("experiments","scienceExperiment"),UsedImplicitly] + public class ExperimentRuleset : IPatcherRuleSet + { + /// + public bool Matches(string label) => label == "scienceExperiment"; + + /// + public ISelectable ConvertToSelectable(string type, string name, string jsonData) => + new ExperimentSelectable(JObject.Parse(jsonData)); + + /// + public INewAsset CreateNew(List dataValues) + { + var core = new ExperimentCore + { + data = new ExperimentDefinition + { + ExperimentID = dataValues[0].String + } + }; + return new NewGenericAsset("scienceExperiment", dataValues[0].String, + new ExperimentSelectable(JObject.FromObject(core))); + } + } +} \ No newline at end of file diff --git a/Runtime/Science/Rulesets/ExperimentRuleset.cs.meta b/Runtime/Science/Rulesets/ExperimentRuleset.cs.meta new file mode 100644 index 0000000..eb3868b --- /dev/null +++ b/Runtime/Science/Rulesets/ExperimentRuleset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a5d1bb21d397801419d41e2274db379a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Rulesets/RegionsRuleset.cs b/Runtime/Science/Rulesets/RegionsRuleset.cs new file mode 100644 index 0000000..29069d9 --- /dev/null +++ b/Runtime/Science/Rulesets/RegionsRuleset.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using KSP.Game.Science; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; +using PatchManager.Science.Selectables; + +namespace PatchManager.Science.Rulesets +{ + /// + /// Ruleset for science regions + /// + [PatcherRuleset("regions","science_region")] + public class RegionsRuleset : IPatcherRuleSet + { + /// + public bool Matches(string label) => label == "science_region"; + + /// + public ISelectable ConvertToSelectable(string type, string name, string jsonData) => + new RegionsSelectable(JObject.Parse(jsonData)); + + /// + public INewAsset CreateNew(List dataValues) + { + var bodyName = dataValues[0].String; + var bakedDiscoverables = new CelestialBodyScienceRegionsData + { + BodyName = bodyName, + SituationData = new CBSituationData(), + Regions = Array.Empty(), + Version = dataValues.Count > 1 ? dataValues[1].String : "0.1" + }; + return new NewGenericAsset("science_region", + $"{bodyName.ToLowerInvariant()}_science_regions", + new RegionsSelectable(JObject.FromObject(bakedDiscoverables))); + } + } +} \ No newline at end of file diff --git a/Runtime/Science/Rulesets/RegionsRuleset.cs.meta b/Runtime/Science/Rulesets/RegionsRuleset.cs.meta new file mode 100644 index 0000000..8355e3c --- /dev/null +++ b/Runtime/Science/Rulesets/RegionsRuleset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6a954a8b9c204ea4ea95f8f5bff87280 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Rulesets/ScienceRuleset.cs b/Runtime/Science/Rulesets/ScienceRuleset.cs new file mode 100644 index 0000000..0d31efe --- /dev/null +++ b/Runtime/Science/Rulesets/ScienceRuleset.cs @@ -0,0 +1,31 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Attributes; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.NewAssets; +using PatchManager.Science.Selectables; + +namespace PatchManager.Science.Rulesets +{ + /// + /// This ruleset is used to patch the science tech tree. + /// + [PatcherRuleset("science","techNodeData")] + public class ScienceRuleset : IPatcherRuleSet + { + /// + public bool Matches(string label) => label == "techNodeData"; + + /// + public ISelectable ConvertToSelectable(string type, string name, string jsonData) => + new ScienceSelectable(JObject.Parse(jsonData)); + + /// + public INewAsset CreateNew(List dataValues) + { + return new NewGenericAsset("techNodeData", dataValues[0].String, + new ScienceSelectable(JObject.Parse($"{{\n \"Version\": 12,\n \"ID\": \"{dataValues[0].String}\",\n \"NameLocKey\": \"Science/TechNodes/Names/tNode_4v_docking_01\",\n \"IconID\": \"ICO-RDCenter-Docking-24x\",\n \"CategoryID\": \"\",\n \"HiddenByNodeID\": \"\",\n \"DescriptionLocKey\": \"Science/TechNodes/Descriptions/tNode_4v_docking_01\",\n \"RequiredSciencePoints\": 7000,\n \"UnlockedPartsIDs\": [\n \"dockingring_4v_inline\",\n \"dockingport_3v_inline\"\n ],\n \"RequiredTechNodeIDs\": [\n \"tNode_4v_decouplers_01\"\n ],\n \"TierToUnlock\": 0,\n \"TechTreePosition\": {{\n \"x\": 5220.0,\n \"y\": 310.0\n }}\n}}"))); + } + } +} \ No newline at end of file diff --git a/Runtime/Science/Rulesets/ScienceRuleset.cs.meta b/Runtime/Science/Rulesets/ScienceRuleset.cs.meta new file mode 100644 index 0000000..4e23ede --- /dev/null +++ b/Runtime/Science/Rulesets/ScienceRuleset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a20e0797c3aaa8746825e95dc117969d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/ScienceModule.cs b/Runtime/Science/ScienceModule.cs new file mode 100644 index 0000000..fd2883f --- /dev/null +++ b/Runtime/Science/ScienceModule.cs @@ -0,0 +1,13 @@ +using JetBrains.Annotations; +using PatchManager.Shared.Modules; + +namespace PatchManager.Science +{ + /// + /// The science module. + /// + [UsedImplicitly] + public class ScienceModule : BaseModule + { + } +} \ No newline at end of file diff --git a/Runtime/Science/ScienceModule.cs.meta b/Runtime/Science/ScienceModule.cs.meta new file mode 100644 index 0000000..d1b16fe --- /dev/null +++ b/Runtime/Science/ScienceModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 295f2e81c164567418ebea73960aba3a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Selectables.meta b/Runtime/Science/Selectables.meta new file mode 100644 index 0000000..839706d --- /dev/null +++ b/Runtime/Science/Selectables.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 774042ed78841cd46a884a1584312056 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Selectables/DiscoverablesSelectable.cs b/Runtime/Science/Selectables/DiscoverablesSelectable.cs new file mode 100644 index 0000000..af2e8a4 --- /dev/null +++ b/Runtime/Science/Selectables/DiscoverablesSelectable.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using KSP.Game.Science; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Selectables; +using PatchManager.Science.Modifiables; + +namespace PatchManager.Science.Selectables +{ + /// + /// A selectable that represents discoverables + /// + public sealed class DiscoverablesSelectable : BaseSelectable + { +#pragma warning disable CS0414 // Field is assigned but its value is never used + private bool _modified; +#pragma warning restore CS0414 // Field is assigned but its value is never used + private bool _deleted; + + /// + /// Marks this part selectable as having been modified any level down + /// + public void SetModified() + { + _modified = true; + } + + /// + /// Marks this part as goneso + /// + public void SetDeleted() + { + SetModified(); + _deleted = true; + } + + + /// + /// The main object that represents this discoverable object + /// + public JObject DiscoverablesObject; + private JArray _discoverablesArray; + + /// + /// Create a new discoverables selectable from a JObject + /// + /// Discoverable + public DiscoverablesSelectable(JObject discoverablesObject) + { + DiscoverablesObject = discoverablesObject; + ElementType = "discoverables"; + Name = discoverablesObject["BodyName"].Value(); + Children = new List { }; + Classes = + new List { "BodyName" }; + _discoverablesArray = (JArray)discoverablesObject["Discoverables"]; + foreach (var jToken in _discoverablesArray) + { + var discoverable = (JObject)jToken; + var name = discoverable["ScienceRegionId"]!.Value(); + Classes.Add(name); + Children.Add(new JTokenSelectable(SetModified, discoverable, + disc => ((JObject)disc)["ScienceRegionId"]!.Value(), "discoverable")); + } + } + + /// + public override List Children { get; } + + /// + public override string Name { get; } + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + foreach (var jToken in _discoverablesArray) + { + var discoverable = (JObject)jToken; + var name = discoverable["ScienceRegionId"]!.Value(); + if (name != @class) continue; + classValue = DataValue.FromJToken(discoverable); + return true; + } + classValue = DataValue.Null; + return false; + } + + /// + public override bool IsSameAs(ISelectable other) => other is DiscoverablesSelectable discoverablesSelectable && + discoverablesSelectable.DiscoverablesObject == + DiscoverablesObject; + + /// + public override IModifiable OpenModification() => new DiscoverablesModifiable(this); + + /// + public override ISelectable AddElement(string elementType) + { + var position = new CelestialBodyDiscoverablePosition + { + ScienceRegionId = elementType, + Position = new Vector3d(), + Radius = 0.0 + }; + var jObject = JObject.FromObject(position); + _discoverablesArray.Add(jObject); + var selectable = new JTokenSelectable(SetModified, jObject, + disc => ((JObject)disc)["ScienceRegionId"]!.Value(), "discoverable"); + Classes.Add(elementType); + Children.Add(selectable); + return selectable; + } + + /// + public override string Serialize() => _deleted ? "" : DiscoverablesObject.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(DiscoverablesObject); + + /// + public override string ElementType { get; } + } +} \ No newline at end of file diff --git a/Runtime/Science/Selectables/DiscoverablesSelectable.cs.meta b/Runtime/Science/Selectables/DiscoverablesSelectable.cs.meta new file mode 100644 index 0000000..387878b --- /dev/null +++ b/Runtime/Science/Selectables/DiscoverablesSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 82f96969c4be42d4bb1bb99734f498ac +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Selectables/ExperimentSelectable.cs b/Runtime/Science/Selectables/ExperimentSelectable.cs new file mode 100644 index 0000000..e638af0 --- /dev/null +++ b/Runtime/Science/Selectables/ExperimentSelectable.cs @@ -0,0 +1,113 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Selectables; +using PatchManager.Science.Modifiables; + +namespace PatchManager.Science.Selectables +{ + /// + /// A selectable that represents a science experiment + /// + public class ExperimentSelectable : BaseSelectable + { +#pragma warning disable CS0414 // Field is assigned but its value is never used + private bool _modified; +#pragma warning restore CS0414 // Field is assigned but its value is never used + private bool _deleted; + + /// + /// Marks this part selectable as having been modified any level down + /// + public void SetModified() + { + _modified = true; + } + + /// + /// Marks this part as goneso + /// + public void SetDeleted() + { + SetModified(); + _deleted = true; + } + + /// + /// The science object that this selectable represents + /// + public JObject ScienceObject; + + /// + /// The data object that this selectable represents + /// + public JObject DataObject; + + /// + /// Creates a new experiment selectable + /// + /// The science data that this selectable represents + public ExperimentSelectable(JObject scienceData) + { + ElementType = "scienceExperiment"; + ScienceObject = scienceData; + DataObject = (JObject)scienceData["data"]!; + Classes = new List { }; + Children = new List { }; + foreach (var subToken in DataObject) + { + Classes.Add(subToken.Key); + Children.Add(new JTokenSelectable(SetModified,subToken.Value,subToken.Key)); + } + } + + /// + public sealed override List Children { get; } + + /// + public override string Name => DataObject["ExperimentID"]!.Value()!; + + /// + public sealed override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + classValue = null; + if (!MatchesClass(@class)) + { + return false; + } + + classValue = DataValue.FromJToken(DataObject[@class]); + return true; + } + + /// + public override string ElementType { get; } + + /// + public override bool IsSameAs(ISelectable other) => + other is ScienceSelectable selectable && selectable.ScienceObject == ScienceObject; + + /// + public override IModifiable OpenModification() => new ExperimentModifiable(this); + + /// + public override ISelectable AddElement(string elementType) + { + var obj = new JObject(); + DataObject[elementType] = obj; + var n = new JTokenSelectable(SetModified, obj, elementType); + Children.Add(n); + return n; + } + + /// + public override string Serialize() => _deleted ? "" : ScienceObject.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(DataObject); + } +} \ No newline at end of file diff --git a/Runtime/Science/Selectables/ExperimentSelectable.cs.meta b/Runtime/Science/Selectables/ExperimentSelectable.cs.meta new file mode 100644 index 0000000..2dcd343 --- /dev/null +++ b/Runtime/Science/Selectables/ExperimentSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 658e2dc164f5ba0468c6100075ae9fe5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Selectables/RegionsSelectable.cs b/Runtime/Science/Selectables/RegionsSelectable.cs new file mode 100644 index 0000000..dc49a4e --- /dev/null +++ b/Runtime/Science/Selectables/RegionsSelectable.cs @@ -0,0 +1,127 @@ +using System.Collections.Generic; +using KSP.Game.Science; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Selectables; +using PatchManager.Science.Modifiables; + +namespace PatchManager.Science.Selectables +{ + /// + /// This is the selectable for science regions + /// + public sealed class RegionsSelectable : BaseSelectable + { +#pragma warning disable CS0414 // Field is assigned but its value is never used + private bool _modified; +#pragma warning restore CS0414 // Field is assigned but its value is never used + private bool _deleted; + + /// + /// Marks this part selectable as having been modified any level down + /// + public void SetModified() + { + _modified = true; + } + + /// + /// Marks this part as goneso + /// + public void SetDeleted() + { + SetModified(); + _deleted = true; + } + + + /// + /// The main object that represents this discoverable object + /// + public JObject RegionsObject; + private JArray _regionsArray; + + /// + /// Create a new regions selectable from a JObject + /// + /// Region + public RegionsSelectable(JObject regionsObject) + { + RegionsObject = regionsObject; + ElementType = "regions"; + Name = regionsObject["BodyName"].Value(); + Children = new List + { new JTokenSelectable(SetModified, regionsObject["SituationData"], "SituationData", "SituationData") }; + Classes = new List { "BodyName", "SituationData" }; + _regionsArray = (JArray)regionsObject["Regions"]; + foreach (var jToken in _regionsArray) + { + var discoverable = (JObject)jToken; + var name = discoverable["Id"]!.Value(); + Classes.Add(name); + Children.Add(new JTokenSelectable(SetModified, discoverable, + disc => ((JObject)disc)["Id"]!.Value(), "region")); + } + } + + /// + public override List Children { get; } + + /// + public override string Name { get; } + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + foreach (var jToken in _regionsArray) + { + var discoverable = (JObject)jToken; + var name = discoverable["Id"]!.Value(); + if (name != @class) continue; + classValue = DataValue.FromJToken(discoverable); + return true; + } + classValue = DataValue.Null; + return false; + } + + /// + public override bool IsSameAs(ISelectable other) => other is RegionsSelectable regionsSelectable && + regionsSelectable.RegionsObject == + RegionsObject; + + /// + public override IModifiable OpenModification() => new RegionsModifiable(this); + + /// + public override ISelectable AddElement(string elementType) + { + var position = new CelestialBodyDiscoverablePosition + { + ScienceRegionId = elementType, + Position = new Vector3d(), + Radius = 0.0 + }; + var jObject = JObject.FromObject(position); + _regionsArray.Add(jObject); + var selectable = new JTokenSelectable(SetModified, jObject, + disc => ((JObject)disc)["ScienceRegionID"]!.Value(), "discoverable"); + Classes.Add(elementType); + Children.Add(selectable); + return selectable; + } + + /// + public override string Serialize() => _deleted ? "" : RegionsObject.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(RegionsObject); + + /// + public override string ElementType { get; } + } +} \ No newline at end of file diff --git a/Runtime/Science/Selectables/RegionsSelectable.cs.meta b/Runtime/Science/Selectables/RegionsSelectable.cs.meta new file mode 100644 index 0000000..5ce9c16 --- /dev/null +++ b/Runtime/Science/Selectables/RegionsSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a782486ec3d5a5a4786aa4aa6db2dd9f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Science/Selectables/ScienceSelectable.cs b/Runtime/Science/Selectables/ScienceSelectable.cs new file mode 100644 index 0000000..37b4954 --- /dev/null +++ b/Runtime/Science/Selectables/ScienceSelectable.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using PatchManager.SassyPatching; +using PatchManager.SassyPatching.Interfaces; +using PatchManager.SassyPatching.Selectables; +using PatchManager.Science.Modifiables; + +namespace PatchManager.Science.Selectables +{ + /// + /// A selectable that represents a science experiment + /// + public sealed class ScienceSelectable : BaseSelectable + { +#pragma warning disable CS0414 // Field is assigned but its value is never used + private bool _modified; +#pragma warning restore CS0414 // Field is assigned but its value is never used + private bool _deleted; + + /// + /// Marks this part selectable as having been modified any level down + /// + public void SetModified() + { + _modified = true; + } + + /// + /// Marks this part as goneso + /// + public void SetDeleted() + { + SetModified(); + _deleted = true; + } + + /// + /// The science object that this selectable represents + /// + public JObject ScienceObject; + + /// + /// Creates a new science selectable + /// + /// The science data that this selectable represents + public ScienceSelectable(JObject scienceData) + { + ElementType = "techNodeData"; + ScienceObject = scienceData; + Classes = new List(); + Children = new List(); + foreach (var subToken in ScienceObject) + { + Classes.Add(subToken.Key); + Children.Add(new JTokenSelectable(SetModified, subToken.Value, subToken.Key)); + } + } + + /// + public override List Children { get; } + + /// + public override string Name => ScienceObject["ID"]!.Value()!; + + /// + public override List Classes { get; } + + /// + public override bool MatchesClass(string @class, out DataValue classValue) + { + classValue = null; + if (!MatchesClass(@class)) + { + return false; + } + + classValue = DataValue.FromJToken(ScienceObject[@class]); + return true; + } + + /// + public override string ElementType { get; } + + /// + public override bool IsSameAs(ISelectable other) => + other is ScienceSelectable selectable && selectable.ScienceObject == ScienceObject; + + /// + public override IModifiable OpenModification() => new ScienceModifiable(this); + + /// + public override ISelectable AddElement(string elementType) + { + var obj = new JObject(); + ScienceObject[elementType] = obj; + var n = new JTokenSelectable(SetModified, obj, elementType); + Children.Add(n); + return n; + } + + /// + public override string Serialize() => _deleted ? "" : ScienceObject.ToString(); + + /// + public override DataValue GetValue() => DataValue.FromJToken(ScienceObject); + } +} \ No newline at end of file diff --git a/Runtime/Science/Selectables/ScienceSelectable.cs.meta b/Runtime/Science/Selectables/ScienceSelectable.cs.meta new file mode 100644 index 0000000..f201b3d --- /dev/null +++ b/Runtime/Science/Selectables/ScienceSelectable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3190783a42d560549a791aadb6bf497e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Shared.meta b/Runtime/Shared.meta new file mode 100644 index 0000000..3e71e99 --- /dev/null +++ b/Runtime/Shared.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7ec34425e0d04e70b202b856c44c9835 +timeCreated: 1739382719 \ No newline at end of file diff --git a/Runtime/Shared/Extensions.cs b/Runtime/Shared/Extensions.cs new file mode 100644 index 0000000..43e3b23 --- /dev/null +++ b/Runtime/Shared/Extensions.cs @@ -0,0 +1,132 @@ +using System.Collections.Generic; +using UniLinq; + +namespace PatchManager.Shared +{ + /// + /// Utility extension methods for various types. + /// + public static class Extensions + { + /// + /// Deconstructs a into its key and value. + /// + /// Key-value pair to deconstruct. + /// The deconstructed key. + /// The deconstructed value. + /// Type of the key. + /// Type of the value. + public static void Deconstruct( + this KeyValuePair keyValuePair, + out TKey key, + out TValue value + ) + { + key = keyValuePair.Key; + value = keyValuePair.Value; + } + + /// + /// Adds the contents of an of type + /// to a . + /// + /// Target dictionary to add to. + /// Source enumerable to add from. + /// Type of the key. + /// Type of the value. + public static void AddRangeUnique( + this Dictionary target, + IEnumerable> source + ) + { + foreach (var kvp in source) + { + if (target.ContainsKey(kvp.Key)) + { + continue; + } + + target.Add(kvp.Key, kvp.Value); + } + } + + /// + /// Adds the contents of an of type + /// to a . If the key already exists, the contents of the value + /// enumerable will be added to the existing value enumerable. + /// + /// Target dictionary to add to. + /// Source enumerable to add from. + /// Type of the key. + /// Type of the value . + public static void AddRangeMerge( + this Dictionary> target, + IEnumerable>> source + ) + { + foreach (var kvp in source) + { + if (target.ContainsKey(kvp.Key)) + { + target[kvp.Key] = target[kvp.Key].Concat(kvp.Value); + continue; + } + + target.Add(kvp.Key, kvp.Value); + } + } + + /// + /// Gets the relative path to a working directory with both paths expressed as strings + /// + /// + /// + /// + public static string MakeRelativePathTo(this string fullPath, string workingDirectory) + { + string result = string.Empty; + int offset; + + // this is the easy case. The file is inside of the working directory. + if( fullPath.StartsWith(workingDirectory) ) + { + return fullPath.Substring(workingDirectory.Length + 1); + } + + // the hard case has to back out of the working directory + string[] baseDirs = workingDirectory.Split(':', '\\', '/'); + string[] fileDirs = fullPath.Split(':', '\\', '/'); + + // if we failed to split (empty strings?) or the drive letter does not match + if( baseDirs.Length <= 0 || fileDirs.Length <= 0 || baseDirs[0] != fileDirs[0] ) + { + // can't create a relative path between separate harddrives/partitions. + return fullPath; + } + + // skip all leading directories that match + for (offset = 1; offset < baseDirs.Length; offset++) + { + if (baseDirs[offset] != fileDirs[offset]) + break; + } + + // back out of the working directory + for (int i = 0; i < (baseDirs.Length - offset); i++) + { + result += "..\\"; + } + + // step into the file path + for (int i = offset; i < fileDirs.Length-1; i++) + { + result += fileDirs[i] + "\\"; + } + + // append the file + result += fileDirs[fileDirs.Length - 1]; + + return result; + } + } +} \ No newline at end of file diff --git a/Runtime/Shared/Extensions.cs.meta b/Runtime/Shared/Extensions.cs.meta new file mode 100644 index 0000000..33b695b --- /dev/null +++ b/Runtime/Shared/Extensions.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7b7af9197c73372418c95320555ea6f9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Shared/Interfaces.meta b/Runtime/Shared/Interfaces.meta new file mode 100644 index 0000000..b55e450 --- /dev/null +++ b/Runtime/Shared/Interfaces.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7c3133a20b629d248a09e7b33d808636 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Shared/Interfaces/ITextAssetGenerator.cs b/Runtime/Shared/Interfaces/ITextAssetGenerator.cs new file mode 100644 index 0000000..b206105 --- /dev/null +++ b/Runtime/Shared/Interfaces/ITextAssetGenerator.cs @@ -0,0 +1,21 @@ +namespace PatchManager.Shared.Interfaces +{ + /// + /// Describes a patcher that can generate text assets + /// + public interface ITextAssetGenerator + { + /// + /// The priority of this patcher compared to other patchers, so it can order the way they get executed + /// + public ulong Priority { get; } + + /// + /// Creates a new text asset + /// + /// The label of the created asset + /// The name of the created asset + /// The contents of the created asset + public string Create(out string label, out string name); + } +} \ No newline at end of file diff --git a/Runtime/Shared/Interfaces/ITextAssetGenerator.cs.meta b/Runtime/Shared/Interfaces/ITextAssetGenerator.cs.meta new file mode 100644 index 0000000..8a48c68 --- /dev/null +++ b/Runtime/Shared/Interfaces/ITextAssetGenerator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2edafcb72ca6c6148bd79c841ddce8b7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Shared/Interfaces/ITextPatcher.cs b/Runtime/Shared/Interfaces/ITextPatcher.cs new file mode 100644 index 0000000..5a87498 --- /dev/null +++ b/Runtime/Shared/Interfaces/ITextPatcher.cs @@ -0,0 +1,22 @@ +namespace PatchManager.Shared.Interfaces +{ + /// + /// This interfaces describes a patcher that can patch a simple text asset + /// + public interface ITextPatcher + { + /// + /// The priority of this patcher compared to other patchers, so it can order the way they get executed + /// + public ulong Priority { get; } + + /// + /// Execute this patcher on a blob of text + /// + /// The type of patch, "part" for parts patches, etc... + /// The name of the blob of text being patched + /// The string representation of the file being patched, if it gets set to an empty string, then we should just delete whatever is being patched + /// True if the patchData was modified + public bool TryPatch(string patchType, string name, ref string patchData); + } +} \ No newline at end of file diff --git a/Runtime/Shared/Interfaces/ITextPatcher.cs.meta b/Runtime/Shared/Interfaces/ITextPatcher.cs.meta new file mode 100644 index 0000000..b40782b --- /dev/null +++ b/Runtime/Shared/Interfaces/ITextPatcher.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 2527ff8777b2be542ac2abac380cbc8b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Shared/Logging.cs b/Runtime/Shared/Logging.cs new file mode 100644 index 0000000..6d46490 --- /dev/null +++ b/Runtime/Shared/Logging.cs @@ -0,0 +1,87 @@ +using JetBrains.Annotations; +using ReduxLib.Logging; + +namespace PatchManager.Shared +{ + /// + /// Logging helper class for use in the PatchManager modules. + /// + [PublicAPI] + public static class Logging + { + private static ILogger _logger; + + /// + /// Initializes the logging helper class with a BepInEx log source. + /// + /// Log source to use for logging. + public static void Initialize(ILogger logger) + { + _logger = logger; + } + + /// + /// Logs a message with the specified log level. + /// + /// Log level of the message. + /// Message to be logged. + public static void Log(LogLevel level, object message) + { + _logger.Log(level, message); + } + + /// + /// Logs a debug message. + /// + /// Message to be logged. + public static void LogDebug(object message) + { + Log(LogLevel.Debug, message); + } + + /// + /// Logs a message-level message. + /// + /// Message to be logged. + public static void LogMessage(object message) + { + Log(LogLevel.Message, message); + } + + /// + /// Logs an info message. + /// + /// Message to be logged. + public static void LogInfo(object message) + { + Log(LogLevel.Info, message); + } + + /// + /// Logs a warning message. + /// + /// Message to be logged. + public static void LogWarning(object message) + { + Log(LogLevel.Warning, message); + } + + /// + /// Logs an error message. + /// + /// Message to be logged. + public static void LogError(object message) + { + Log(LogLevel.Error, message); + } + + /// + /// Logs a fatal message. Only used in the case of fatal errors that will force the game to crash. + /// + /// Message to be logged. + public static void LogFatal(object message) + { + Log(LogLevel.Fatal, message); + } + } +} \ No newline at end of file diff --git a/Runtime/Shared/Logging.cs.meta b/Runtime/Shared/Logging.cs.meta new file mode 100644 index 0000000..558bd2a --- /dev/null +++ b/Runtime/Shared/Logging.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4b6710b2a1ff0aa44ad085c4be0be348 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Shared/Modules.meta b/Runtime/Shared/Modules.meta new file mode 100644 index 0000000..d4bd05a --- /dev/null +++ b/Runtime/Shared/Modules.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 79bddb941e2a09a4ab5d944e4e8011e5 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Shared/Modules/BaseModule.cs b/Runtime/Shared/Modules/BaseModule.cs new file mode 100644 index 0000000..2a682a0 --- /dev/null +++ b/Runtime/Shared/Modules/BaseModule.cs @@ -0,0 +1,36 @@ +using ReduxLib.Configuration; +using UnityEngine.UIElements; + +namespace PatchManager.Shared.Modules +{ + /// + /// Base class for PatchManager modules. + /// + public class BaseModule : IModule + { + /// + public virtual void Init() + { + } + + /// + public virtual void Load() + { + } + + /// + public virtual void PreLoad() + { + + } + + /// + public virtual VisualElement GetDetails() => null; + + + /// + public virtual void BindConfiguration(IConfigFile modConfiguration) + { + } + } +} \ No newline at end of file diff --git a/Runtime/Shared/Modules/BaseModule.cs.meta b/Runtime/Shared/Modules/BaseModule.cs.meta new file mode 100644 index 0000000..20ca94c --- /dev/null +++ b/Runtime/Shared/Modules/BaseModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b4ea9660145cd8045947bc7cef146366 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Shared/Modules/IModule.cs b/Runtime/Shared/Modules/IModule.cs new file mode 100644 index 0000000..710e398 --- /dev/null +++ b/Runtime/Shared/Modules/IModule.cs @@ -0,0 +1,43 @@ +using JetBrains.Annotations; +using ReduxLib.Configuration; +using UnityEngine.UIElements; + +namespace PatchManager.Shared.Modules +{ + /// + /// Base interface for PatchManager DLL modules. + /// + public interface IModule + { + /// + /// Called in the mod's Start method before the game is loaded. + /// Use this method to register actions with the FlowManager. + /// + public void Init(); + + /// + /// Called in mod's OnPreInitialized method after the game is loaded. + /// Use this to register resource locators and do things that require the GameInstance. + /// + public void PreLoad(); + + /// + /// Called in mod's OnInitialized method after the game is loaded. + /// Use this to register resource locators and do things that require the GameInstance. + /// + public void Load(); + + /// + /// Called when getting the details information for patch manager after game load. + /// + /// A visual element describing information about the module or null for no information + [CanBeNull] + public VisualElement GetDetails(); + + /// + /// Called to bind configuration to this module specifically. + /// + /// The configuration of the base Patch Manager mod to bind to + public void BindConfiguration(IConfigFile modConfiguration); + } +} \ No newline at end of file diff --git a/Runtime/Shared/Modules/IModule.cs.meta b/Runtime/Shared/Modules/IModule.cs.meta new file mode 100644 index 0000000..1123cca --- /dev/null +++ b/Runtime/Shared/Modules/IModule.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 900c28bb4cb5154468780e0ee3ed24fb +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Runtime/Shared/Modules/ModuleManager.cs b/Runtime/Shared/Modules/ModuleManager.cs new file mode 100644 index 0000000..c3406ad --- /dev/null +++ b/Runtime/Shared/Modules/ModuleManager.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using JetBrains.Annotations; + +namespace PatchManager.Shared.Modules +{ + /// + /// Manages the loading of PatchManager DLL modules. + /// + internal static class ModuleManager + { + internal static readonly List Modules = new(); + + /// + /// Registers a PatchManager module DLL to be loaded. The module must contain a single class that inherits + /// from . + /// + /// Path to the module DLL file + [PublicAPI] + public static void Register(Type moduleType) + { + if (!typeof(IModule).IsAssignableFrom(moduleType)) + { + Logging.LogError( + $"module type {moduleType} is not a subclass of IModule" + ); + return; + } + + var instance = (IModule)Activator.CreateInstance(moduleType); + Modules.Add(instance); + } + + internal static void InitAll() + { + foreach (var module in Modules) + { + module.Init(); + } + } + + internal static void LoadAll() + { + foreach (var module in Modules) + { + module.Load(); + } + } + + internal static void PreLoadAll() + { + + foreach (var module in Modules) + { + module.PreLoad(); + } + } + } +} \ No newline at end of file diff --git a/Runtime/Shared/Modules/ModuleManager.cs.meta b/Runtime/Shared/Modules/ModuleManager.cs.meta new file mode 100644 index 0000000..492c6b2 --- /dev/null +++ b/Runtime/Shared/Modules/ModuleManager.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 4d790dac5cf27804ead7b5877fd35867 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/StandalonePatchTester/Program.cs b/StandalonePatchTester/Program.cs deleted file mode 100644 index f760b89..0000000 --- a/StandalonePatchTester/Program.cs +++ /dev/null @@ -1,86 +0,0 @@ -// See https://aka.ms/new-console-template for more information - -using System.Reflection; -using PatchManager.SassyPatching.Execution; -using PatchManager.Shared.Interfaces; - -//Assert that the assembly we want is loaded for testing -Assembly.Load("PatchManager.Parts"); - -if (Directory.Exists("json") && Directory.Exists("patches")) -{ - if (Directory.Exists("patched")) - { - Directory.Delete("patched",true); - } - - Directory.CreateDirectory("patched"); - - List patchers = new(); - - void Add(ITextPatcher patcher) - { - bool inserted = false; - for (int index = 0; index < patchers.Count; index++) - { - if (patchers[index].Priority > patcher.Priority) - { - patchers.Insert(index, patcher); - inserted = true; - break; - } - } - - if (!inserted) - { - patchers.Add(patcher); - } - } - - void AddGenerator(ITextAssetGenerator generator) - { - - } - - var universe = new Universe(Add, Console.WriteLine, Console.WriteLine, AddGenerator, new()); - universe.LoadPatchesInDirectory(new DirectoryInfo("patches"), "test"); - - Console.WriteLine($"{universe.AllLibraries.Count} libraries loaded!"); - universe.RegisterAllPatches(); - Console.WriteLine($"{patchers.Count} patcher(s) registered!"); - var numPatchesRan = 0; - var jsonInfo = new DirectoryInfo("json"); - foreach (var part in jsonInfo.EnumerateFiles("*.json")) - { - // if (!part.Name.StartsWith("fueltank")) continue; - var localPatchesRan = 0; - Console.WriteLine($"Running patchers on {part.Name}"); - string text = File.ReadAllText(part.FullName); - foreach (var patcher in patchers) - { - var copy = new string(text); - try - { - var patched = patcher.TryPatch("parts_data",Path.GetFileNameWithoutExtension(part.Name), ref text); - if (patched) localPatchesRan++; - } - catch (Exception e) - { - Console.WriteLine($"Patch errored due to: {e.Message}"); - text = copy; - } - } - Console.WriteLine($"{localPatchesRan} patch(es) ran on {part.Name}"); - if (localPatchesRan > 0) - { - File.WriteAllText(Path.Combine("patched", part.Name), text); - } - numPatchesRan += localPatchesRan; - - } - Console.WriteLine($"{numPatchesRan} patch(es) ran in total"); -} -else -{ - Console.WriteLine("Usage: run this program in a folder that has a json/ subfolder and a patches/ subfolder and it will run every patch in the patches folder and output patched files into patched/"); -} \ No newline at end of file diff --git a/StandalonePatchTester/StandalonePatchTester.csproj b/StandalonePatchTester/StandalonePatchTester.csproj deleted file mode 100644 index c61cf9f..0000000 --- a/StandalonePatchTester/StandalonePatchTester.csproj +++ /dev/null @@ -1,20 +0,0 @@ - - - - - Exe - net6.0 - enable - enable - $(SolutionDir)/build/bin/testing/$(MSBuildProjectName) - $(SolutionDir)build/obj/testing/$(MSBuildProjectName) - $(NoWarn);MSB3539 - - - - - - - - - diff --git a/images.meta b/images.meta new file mode 100644 index 0000000..1b656d6 --- /dev/null +++ b/images.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 43ea5c79ebdfb7c44ae824502b3c9ef0 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/patch_tests.meta b/patch_tests.meta new file mode 100644 index 0000000..579e658 --- /dev/null +++ b/patch_tests.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c1fa2b6df7bbb0b449a1402a80de1edd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/patch_tests/json.meta b/patch_tests/json.meta new file mode 100644 index 0000000..0490889 --- /dev/null +++ b/patch_tests/json.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0068e3d0481b2bd43b9ae0e2707cc4c6 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/patch_tests/patches.meta b/patch_tests/patches.meta new file mode 100644 index 0000000..5ca0694 --- /dev/null +++ b/patch_tests/patches.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f1b809e2c36900944ab5d9b880be6edb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/plugin_template.meta b/plugin_template.meta new file mode 100644 index 0000000..b97b6d3 --- /dev/null +++ b/plugin_template.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f2a043dcf04cc164f9a52fe5bac83590 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/scripts.meta b/scripts.meta new file mode 100644 index 0000000..b4940c9 --- /dev/null +++ b/scripts.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8df77cd1c0647eb42b2a99b94d9ca4bc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/src/PatchManager.Core/Assets/ArchiveResourceLocator.cs b/src/PatchManager.Core/Assets/ArchiveResourceLocator.cs deleted file mode 100644 index a14e7f7..0000000 --- a/src/PatchManager.Core/Assets/ArchiveResourceLocator.cs +++ /dev/null @@ -1,58 +0,0 @@ -using PatchManager.Core.Cache; -using PatchManager.Shared; -using UnityEngine; -using UnityEngine.AddressableAssets.ResourceLocators; -using UnityEngine.ResourceManagement.ResourceLocations; - -namespace PatchManager.Core.Assets; - -/// -/// Locates assets in archives of cached assets. -/// -internal class ArchiveResourceLocator : IResourceLocator -{ - /// - /// The ID of the locator. - /// - public string LocatorId => GetType().FullName; - - /// - /// The labels registered in the locator. - /// - public IEnumerable Keys => CacheManager.Inventory.CacheEntries.Keys; - - /// - /// Locates an asset file in a cache archive by its label and type. - /// - /// Label to find. - /// Type of assets to find. - /// List of found locations. - /// - public bool Locate(object key, Type type, out IList locations) - { - var label = key.ToString(); - if (!CacheManager.Inventory.CacheEntries.TryGetValue(label, out var cacheEntry)) - { - locations = new List(); - return false; - } - - locations = cacheEntry.Assets - .Select(asset => new ResourceLocationBase( - cacheEntry.ArchiveFilename, - asset, - typeof(ArchiveResourceProvider).FullName, - typeof(TextAsset) - )) - .Cast() - .ToList(); - - if (locations.Count == 0) - { - return false; - } - - Logging.LogDebug($"Located key '{key}' with {locations.Count} locations."); - return true; - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Assets/ArchiveResourceProvider.cs b/src/PatchManager.Core/Assets/ArchiveResourceProvider.cs deleted file mode 100644 index cbc1fa0..0000000 --- a/src/PatchManager.Core/Assets/ArchiveResourceProvider.cs +++ /dev/null @@ -1,38 +0,0 @@ -using PatchManager.Core.Cache; -using PatchManager.Shared; -using UnityEngine; -using UnityEngine.ResourceManagement.ResourceProviders; - -namespace PatchManager.Core.Assets; - -/// -/// Provides assets found by . -/// -internal class ArchiveResourceProvider : ResourceProviderBase -{ - /// - /// Provides assets found by . - /// - /// Information about the asset to be provided. - public override void Provide(ProvideHandle provideHandle) - { - try - { - var archiveName = provideHandle.Location.PrimaryKey; - var file = provideHandle.Location.InternalId; - Logging.LogDebug($"Loading {archiveName}/{file}"); - - var archive = CacheManager.GetArchive(archiveName); - var asset = new TextAsset(archive.ReadFile(file)) - { - name = Path.GetFileName(file) - }; - provideHandle.Complete(asset, true, null); - } - catch (Exception e) - { - Logging.LogError(e); - provideHandle.Complete(null, false, e); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Assets/Locators.cs b/src/PatchManager.Core/Assets/Locators.cs deleted file mode 100644 index 764dc80..0000000 --- a/src/PatchManager.Core/Assets/Locators.cs +++ /dev/null @@ -1,40 +0,0 @@ -using UnityEngine; -using UnityEngine.AddressableAssets.ResourceLocators; -using UnityEngine.ResourceManagement.ResourceLocations; - -namespace PatchManager.Core.Assets; - -/// -/// A class that holds all the custom resource locators for patched asset files. -/// -public static class Locators -{ - private static readonly List ResourceLocators = new(); - - /// - /// Register a custom resource locator. - /// - /// Locator to register. - public static void Register(IResourceLocator locator) - { - ResourceLocators.Add(locator); - } - - /// - /// Locate assets by label. - /// - /// Label of the assets to be located. - /// List of locations of the found assets. - /// True if any assets were found, false otherwise. - public static bool LocateAll(object label, out List locations) - { - locations = new List(); - foreach (var locator in ResourceLocators) - { - locator.Locate(label, typeof(TextAsset), out var foundLocations); - locations.AddRange(foundLocations); - } - - return locations.Count > 0; - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Assets/PatchingManager.cs b/src/PatchManager.Core/Assets/PatchingManager.cs deleted file mode 100644 index 2939f35..0000000 --- a/src/PatchManager.Core/Assets/PatchingManager.cs +++ /dev/null @@ -1,356 +0,0 @@ -using System.Collections; -using KSP.Game; -using KSP.Game.Flow; -using MonoMod.Utils; -using PatchManager.Core.Cache; -using PatchManager.Core.Cache.Json; -using PatchManager.Core.Patches.Runtime; -using PatchManager.Core.Utility; -using PatchManager.SassyPatching.Execution; -using PatchManager.Shared; -using PatchManager.Shared.Interfaces; -using SpaceWarp.API.Mods; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.ResourceManagement.AsyncOperations; - -namespace PatchManager.Core.Assets; - -internal static class PatchingManager -{ - internal static readonly List Patchers = new(); - internal static readonly List Generators = new(); - internal static Universe Universe; - - private static readonly PatchHashes CurrentPatchHashes = PatchHashes.CreateDefault(); - - private static int _initialLibraryCount; - private static Dictionary> _createdAssets = new(); - - internal static int TotalPatchCount; - internal static int TotalErrorCount; - - public static void GenerateUniverse(HashSet singleFileModIds) - { - var loadedPlugins = PluginList.AllEnabledAndActivePlugins.Select(x => x.Guid).ToList(); - loadedPlugins.AddRange(singleFileModIds); - Universe = new(RegisterPatcher, Logging.LogError, Logging.LogMessage, RegisterGenerator, - loadedPlugins); - _initialLibraryCount = Universe.AllLibraries.Count; - } - - private static void RegisterPatcher(ITextPatcher patcher) - { - for (var index = 0; index < Patchers.Count; index++) - { - if (Patchers[index].Priority <= patcher.Priority) - { - continue; - } - - Patchers.Insert(index, patcher); - return; - } - - Patchers.Add(patcher); - } - - private static void RegisterGenerator(ITextAssetGenerator generator) - { - for (var index = 0; index < Generators.Count; index++) - { - if (Generators[index].Priority <= generator.Priority) - { - continue; - } - - Generators.Insert(index, generator); - return; - } - - Generators.Add(generator); - } - - private static string PatchJson(string label, string assetName, string text) - { - Console.WriteLine($"Patching {label}:{assetName}"); - var patchCount = 0; - - foreach (var patcher in Patchers) - { - var backup = text; - try - { - var wasPatched = patcher.TryPatch(label, assetName, ref text); - if (wasPatched) - { - patchCount++; - } - } - catch (Exception e) - { - TotalErrorCount += 1; - Console.WriteLine($"Patch of {label}:{assetName} errored due to: {e}"); - text = backup; - } - - if (text == "") - { - break; - } - } - - TotalPatchCount += patchCount; - if (patchCount > 0) - { - Console.WriteLine($"Patched {label}:{assetName} with {patchCount} patches. Total: {TotalPatchCount}"); - } - - return text; - } - - private static int _previousLibraryCount = -1; - - public static void ImportModPatches(string modName, string modFolder) - { - Universe.LoadPatchesInDirectory(new DirectoryInfo(modFolder), modName); - - var currentLibraryCount = Universe.AllLibraries.Count - _initialLibraryCount; - - if (currentLibraryCount > _previousLibraryCount) - { - Logging.LogInfo($"{currentLibraryCount} mod libraries loaded!"); - _previousLibraryCount++; - } - - var patchFiles = Directory.GetFiles(modFolder, "*.patch", SearchOption.AllDirectories); - foreach (var patchFile in patchFiles) - { - var patchHash = Hash.FromFile(patchFile); - CurrentPatchHashes.Patches.Add(patchFile, patchHash); - } - } - - public static void ImportSinglePatch(FileInfo fileInfo) - { - Universe.LoadSinglePatchFile(fileInfo, new DirectoryInfo(BepInEx.Paths.GameRootPath)); - CurrentPatchHashes.Patches.Add(fileInfo.FullName, Hash.FromFile(fileInfo.FullName)); - } - - public static void RegisterPatches() - { - Logging.LogInfo($"Registering all patches!"); - Universe.RegisterAllPatches(); - Logging.LogInfo($"{Patchers.Count} patchers registered!"); - Logging.LogInfo($"{Generators.Count} generators registered!"); - } - - /// - /// Invalidates the cache if the checksum is different. - /// - /// True if the cache is valid, false if it was invalidated. - public static bool InvalidateCacheIfNeeded() - { - var checksum = Hash.FromJsonObject(CurrentPatchHashes); - - if (CacheManager.Inventory.Checksum == checksum) - { - Logging.LogInfo("Cache is valid, skipping rebuild."); - CacheManager.CacheValidLabels.AddRange(CacheManager.Inventory.CacheEntries.Keys); - return true; - } - - Logging.LogInfo("Cache is invalid, rebuilding."); - CacheManager.InvalidateCache(); - CacheManager.Inventory.Checksum = checksum; - CacheManager.Inventory.Patches = CurrentPatchHashes; - - return false; - } - - private static AsyncOperationHandle> RebuildCache(string label) - { - Logging.LogInfo($"Patching: {label}"); - var archiveFilename = $"{label.Replace("/", "")}.zip"; - - var archiveFiles = new Dictionary(); - - var labelCacheEntry = new CacheEntry - { - Label = label, - ArchiveFilename = archiveFilename, - Assets = new List() - }; - var assetsCacheEntries = new Dictionary(); - var unchanged = !_createdAssets.ContainsKey(label); - - - if (_createdAssets.TryGetValue(label, out var createdAsset)) - { - foreach (var (name, text) in createdAsset) - { - var patchedText = PatchJson(label, name, text); - if (patchedText == "") continue; - archiveFiles[name] = patchedText; - labelCacheEntry.Assets.Add(name); - assetsCacheEntries.Add(name, new CacheEntry - { - Label = name, - ArchiveFilename = archiveFilename, - Assets = new List { name } - }); - } - - createdAsset.Clear(); - _createdAssets.Remove(label); - } - - var handle = Addressables.LoadAssetsAsync(label, asset => - { - try - { - var patchedText = PatchJson(label, asset.name, asset.text); - if (patchedText != asset.text) - { - unchanged = false; - } - - // Handle deletion - if (patchedText == "") - { - return; - } - - archiveFiles[asset.name] = patchedText; - labelCacheEntry.Assets.Add(asset.name); - assetsCacheEntries.Add(asset.name, new CacheEntry - { - Label = asset.name, - ArchiveFilename = archiveFilename, - Assets = new List { asset.name } - }); - } - catch (Exception e) - { - Console.WriteLine($"Unable to patch {asset.name} due to: {e.Message}"); - } - }); - - - void SaveArchive() - { - var archive = CacheManager.CreateArchive(archiveFilename); - foreach (var archiveFile in archiveFiles) - { - archive.AddFile(archiveFile.Key, archiveFile.Value); - } - - archive.Save(); - - CacheManager.CacheValidLabels.Add(label); - CacheManager.Inventory.CacheEntries.Add(label, labelCacheEntry); - CacheManager.Inventory.CacheEntries.AddRangeUnique(assetsCacheEntries); - CacheManager.SaveInventory(); - - Console.WriteLine($"Cache for label '{label}' rebuilt."); - } - - if (handle.Status == AsyncOperationStatus.Failed && !unchanged) - { - SaveArchive(); - } - - handle.Completed += results => - { - if (results.Status != AsyncOperationStatus.Succeeded || unchanged) - { - return; - } - - SaveArchive(); - Addressables.Release(results); - }; - - return handle; - } - - public static void CreateNewAssets(Action resolve, Action reject) - { - foreach (var generator in Generators) - { - try - { - var text = generator.Create(out var label, out var name); - Logging.LogDebug($"Generated an asset with the label {label}, and name {name}:\n{text}"); - - if (!_createdAssets.ContainsKey(label)) - _createdAssets[label] = new List<(string name, string text)>(); - _createdAssets[label].Add((name, text)); - } - catch (Exception e) - { - Logging.LogError($"Failed to generate an asset due to: {e}"); - } - } - - resolve(); - } - - public static void RebuildAllCache(Action resolve, Action reject) - { - var distinctKeys = Universe.LoadedLabels.Concat(_createdAssets.Keys).Distinct().ToList(); - - LoadingBarPatch.InjectPatchManagerTips = true; - - GenericFlowAction CreateIndexedFlowAction(int idx) - { - return new GenericFlowAction( - $"Patch Manager: {distinctKeys[idx]}", - (resolve2, _) => - { - var handle = RebuildCache(distinctKeys[idx]); - var killTips = false; - if (idx + 1 < distinctKeys.Count) - { - GameManager.Instance.LoadingFlow._flowActions.Insert( - GameManager.Instance.LoadingFlow._flowIndex + 1, - CreateIndexedFlowAction(idx + 1) - ); - } - else - { - killTips = true; - } - - CoroutineUtil.Instance.DoCoroutine(WaitForCacheRebuildSingleHandle(handle, resolve2, killTips)); - }); - } - - if (distinctKeys.Count > 0) - { - GameManager.Instance.LoadingFlow._flowActions.Insert( - GameManager.Instance.LoadingFlow._flowIndex + 1, - CreateIndexedFlowAction(0) - ); - } - - resolve(); - } - - private static IEnumerator WaitForCacheRebuildSingleHandle( - AsyncOperationHandle> handle, - Action resolve, - bool killLoadingBarTips - ) - { - while (!handle.IsDone) - { - // "Shuffle" it - GameManager.Instance.Game.UI.LoadingBar.ShuffleLoadingTip(); - yield return null; - } - - LoadingBarPatch.InjectPatchManagerTips = !killLoadingBarTips; - resolve(); - } -} diff --git a/src/PatchManager.Core/Cache/Archive.cs b/src/PatchManager.Core/Cache/Archive.cs deleted file mode 100644 index e7e1cc1..0000000 --- a/src/PatchManager.Core/Cache/Archive.cs +++ /dev/null @@ -1,111 +0,0 @@ -using System.IO.Compression; - -namespace PatchManager.Core.Cache; - -/// -/// Wrapper for for use with the caching system. -/// -public class Archive : IDisposable -{ - private readonly string _path; - private readonly MemoryStream _stream; - private bool _isDisposed; - - /// - /// Loads an archive from the given path into memory. - /// - /// Path to the archive file. - /// Whether to create a new archive if it does not exist. - public Archive(string path, bool createNew = false) - { - _path = path; - _stream = new MemoryStream(); - - if (!createNew) - { - using var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read); - fileStream.CopyTo(_stream); - } - - _stream.Seek(0, SeekOrigin.Begin); - } - - /// - /// Disposes the archive object. - /// - public void Dispose() - { - if (_isDisposed) - { - return; - } - _stream.Dispose(); - _isDisposed = true; - - GC.SuppressFinalize(this); - } - - /// - /// Reads the content of the given file in the archive. - /// - /// Path of the file relative to the root of the archive. - /// The full text of the file. - /// Thrown when the file does not exist in the archive. - public string ReadFile(string filePath) - { - AssertNotDisposed(); - - using var archive = new ZipArchive(_stream, ZipArchiveMode.Read, true); - var entry = archive.GetEntry(filePath); - if (entry == null) - { - throw new FileNotFoundException($"File {filePath} does not exist in archive {_path}!"); - } - - using var stream = entry.Open(); - using var reader = new StreamReader(stream); - return reader.ReadToEnd(); - } - - /// - /// Adds a file to the archive. - /// - /// Path of the file relative to the root of the archive. - /// Content of the file. - /// Thrown when the file already exists in the archive. - public void AddFile(string filePath, string content) - { - AssertNotDisposed(); - - using var archive = new ZipArchive(_stream, ZipArchiveMode.Update, true); - - if (archive.GetEntry(filePath) != null) - { - throw new ArgumentException($"File {filePath} already exists in archive {_path}!"); - } - - var entry = archive.CreateEntry(filePath); - using var stream = entry.Open(); - using var writer = new StreamWriter(stream); - writer.Write(content); - } - - /// - /// Saves the archive to disk. - /// - public void Save() - { - AssertNotDisposed(); - using var fileStream = new FileStream(_path, FileMode.Create); - _stream.Seek(0, SeekOrigin.Begin); - _stream.CopyTo(fileStream); - } - - private void AssertNotDisposed() - { - if (_isDisposed) - { - throw new ObjectDisposedException(nameof(Archive), "The Archive object has been disposed."); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Cache/CacheManager.cs b/src/PatchManager.Core/Cache/CacheManager.cs deleted file mode 100644 index fa285f9..0000000 --- a/src/PatchManager.Core/Cache/CacheManager.cs +++ /dev/null @@ -1,83 +0,0 @@ -using System.Reflection; -using PatchManager.Core.Cache.Json; -using PatchManager.Shared; - -namespace PatchManager.Core.Cache; - -internal static class CacheManager -{ - private static readonly string CacheDirectory = Path.Combine( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!, - "cache" - ); - - private static readonly string InventoryPath = Path.Combine(CacheDirectory, "inventory.json"); - - private static readonly Dictionary OpenArchives = new(); - public static readonly List CacheValidLabels = new(); - - private static Inventory _inventory; - public static Inventory Inventory => _inventory ??= Inventory.Load(InventoryPath); - - public static void CreateCacheFolderIfNotExists() - { - if (Directory.Exists(CacheDirectory)) - { - return; - } - - Logging.LogDebug("Cache directory does not exist, creating a new one."); - Directory.CreateDirectory(CacheDirectory); - } - - public static Archive CreateArchive(string archiveFilename) - { - var archivePath = Path.Combine(CacheDirectory, archiveFilename); - if (File.Exists(archivePath)) - { - throw new ArgumentException($"Archive '{archivePath}' already exists!"); - } - - var archive = new Archive(archivePath, true); - OpenArchives.Add(archiveFilename, archive); - return archive; - } - - public static Archive GetArchive(string archiveFilename) - { - var archivePath = Path.Combine(CacheDirectory, archiveFilename); - if (!File.Exists(archivePath)) - { - throw new FileNotFoundException($"Archive '{archivePath}' does not exist!"); - } - - if (!OpenArchives.ContainsKey(archiveFilename)) - { - OpenArchives.Add(archiveFilename, new Archive(archivePath)); - } - - return OpenArchives[archiveFilename]; - } - - public static void InvalidateCache() - { - CacheValidLabels.Clear(); - - _inventory = Inventory.Create(); - - foreach (var archive in OpenArchives.Values) - { - archive.Dispose(); - } - - OpenArchives.Clear(); - - Directory.Delete(CacheDirectory, true); - CreateCacheFolderIfNotExists(); - } - - public static void SaveInventory() - { - Inventory.Save(InventoryPath); - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Cache/Json/CacheEntry.cs b/src/PatchManager.Core/Cache/Json/CacheEntry.cs deleted file mode 100644 index 333032c..0000000 --- a/src/PatchManager.Core/Cache/Json/CacheEntry.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Newtonsoft.Json; - -namespace PatchManager.Core.Cache.Json; - -/// -/// Represents an entry in the cache for a specific asset label. -/// -[JsonObject(MemberSerialization.OptIn)] -public sealed class CacheEntry -{ - /// - /// Label of the asset(s). - /// - [JsonProperty("label", Required = Required.Always)] - public string Label { get; internal set; } - - /// - /// Filename of the archive containing the asset(s). - /// - [JsonProperty("archive", Required = Required.Always)] - public string ArchiveFilename { get; internal set; } - - /// - /// List of all assets in the archive. - /// - [JsonProperty("assets", Required = Required.Always)] - public List Assets { get; internal set; } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Cache/Json/Inventory.cs b/src/PatchManager.Core/Cache/Json/Inventory.cs deleted file mode 100644 index cc343bc..0000000 --- a/src/PatchManager.Core/Cache/Json/Inventory.cs +++ /dev/null @@ -1,91 +0,0 @@ -using Newtonsoft.Json; -using PatchManager.Shared; - -namespace PatchManager.Core.Cache.Json; - -/// -/// Serves as a catalog of all patched labels and their respective archives. -/// -[JsonObject(MemberSerialization.OptIn)] -public sealed class Inventory -{ - /// - /// Dictionary of all patched labels and their respective archives and assets. - /// - [JsonProperty("cache", Required = Required.Always)] - public Dictionary CacheEntries { get; internal set; } - - /// - /// Checksum hash of the patch_hashes field. - /// - [JsonProperty("checksum", Required = Required.Always)] - public string Checksum { get; internal set; } - - /// - /// Dictionary of all patches and their hashes. - /// - [JsonProperty("patch_hashes", Required = Required.Always)] - public PatchHashes Patches { get; internal set; } - - /// - /// Get a by its label. - /// - /// Asset label to get the entry for. - /// A pair of asset label and instance of if found, otherwise null. - public KeyValuePair GetByLabel(string label) - { - return CacheEntries.FirstOrDefault( - entry => entry.Key == label - ); - } - - /// - /// Get a by its archive's name. - /// - /// Archive filename to get the entry for. - /// A pair of asset label and instance of if found, otherwise null. - public KeyValuePair GetByArchive(string archiveFilename) - { - return CacheEntries.FirstOrDefault( - entry => entry.Value.ArchiveFilename == archiveFilename - ); - } - - internal static Inventory Create() - { - return new Inventory - { - CacheEntries = new Dictionary() - }; - } - - internal static Inventory Load(string path) - { - CacheManager.CreateCacheFolderIfNotExists(); - if (!File.Exists(path)) - { - Logging.LogDebug($"Inventory file does not exist, creating new inventory."); - return Create(); - } - - try - { - var inventoryText = File.ReadAllText(path); - var inventory = JsonConvert.DeserializeObject(inventoryText); - Logging.LogDebug("Inventory file loaded successfully."); - return inventory; - } - catch (Exception e) - { - Logging.LogError($"Inventory file was corrupted: {e.Message}"); - return Create(); - } - } - - internal void Save(string path) - { - CacheManager.CreateCacheFolderIfNotExists(); - var inventoryText = JsonConvert.SerializeObject(this, Formatting.Indented); - File.WriteAllText(path, inventoryText); - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Cache/Json/PatchHashes.cs b/src/PatchManager.Core/Cache/Json/PatchHashes.cs deleted file mode 100644 index 75743d2..0000000 --- a/src/PatchManager.Core/Cache/Json/PatchHashes.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Newtonsoft.Json; -using PatchManager.Core.Utility; - -namespace PatchManager.Core.Cache.Json; - -/// -/// Contains hashes of the cache. -/// -[JsonObject(MemberSerialization.OptIn)] -public sealed class PatchHashes -{ - /// - /// KSP 2 version for which the cache was generated. - /// - [JsonProperty("ksp2_version", Required = Required.Always)] - public string Ksp2Version { get; internal set; } - - /// - /// PatchManager version for which the cache was generated. - /// - [JsonProperty("patch_manager_version", Required = Required.Always)] - public string PatchManagerVersion { get; internal set; } - - /// - /// Dictionary of all patches and their hashes. - /// - [JsonProperty("patches", Required = Required.Always)] - public Dictionary Patches { get; internal set; } - - /// - /// Create a default instance of with current KSP 2 and Patch Manager versions. - /// - /// Default instance of - public static PatchHashes CreateDefault() - { - return new PatchHashes - { - Ksp2Version = Versions.Ksp2Version, - PatchManagerVersion = Versions.PatchManagerVersion, - Patches = new Dictionary() - }; - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/CoreModule.cs b/src/PatchManager.Core/CoreModule.cs deleted file mode 100644 index 0c5f084..0000000 --- a/src/PatchManager.Core/CoreModule.cs +++ /dev/null @@ -1,222 +0,0 @@ -using BepInEx; -using JetBrains.Annotations; -using KSP.Game; -using KSP.Game.Flow; -using Newtonsoft.Json; -using PatchManager.Core.Assets; -using PatchManager.Core.Cache; -using PatchManager.Core.Flow; -using PatchManager.SassyPatching.Execution; -using PatchManager.Shared; -using PatchManager.Shared.Modules; -using SpaceWarp.API.Configuration; -using SpaceWarp.API.Mods.JSON; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.UIElements; - -namespace PatchManager.Core; - -/// -/// Core module for PatchManager. -/// -[UsedImplicitly] -public class CoreModule : BaseModule -{ - private ConfigValue _shouldAlwaysInvalidate; - - private bool _wasCacheInvalidated; - - private static bool ShouldLoad(IEnumerable disabled, string modInfoLocation) - { - if (!File.Exists(modInfoLocation)) - return false; - try - { - var metadata = JsonConvert.DeserializeObject(File.ReadAllText(modInfoLocation)); - return metadata.ModID == null || disabled.All(x => x != metadata.ModID); - } - catch - { - return false; - } - } - - private static bool NoSwinfo(DirectoryInfo directory, DirectoryInfo gameRoot) - { - while (directory != null && directory != gameRoot) - { - if (directory.GetFiles().Any(x => x.Name == "swinfo.json")) - return false; - directory = directory.Parent; - } - - return true; - } - - /// - /// Reads all patch files. - /// - public override void Init() - { - if (_shouldAlwaysInvalidate.Value || SpaceWarp.API.Mods.PluginList.ModListChangedSinceLastRun) - { - CacheManager.CreateCacheFolderIfNotExists(); - CacheManager.InvalidateCache(); - } - - var isValid = PatchingManager.InvalidateCacheIfNeeded(); - - if (!isValid) - { - _wasCacheInvalidated = true; - SpaceWarp.API.Loading.Loading.GeneralLoadingActions.Insert(0, - () => new GenericFlowAction("Patch Manager: Creating New Assets", PatchingManager.CreateNewAssets)); - SpaceWarp.API.Loading.Loading.GeneralLoadingActions.Insert(1, - () => new GenericFlowAction("Patch Manager: Rebuilding Cache", PatchingManager.RebuildAllCache)); - SpaceWarp.API.Loading.Loading.GeneralLoadingActions.Insert(2, - () => new GenericFlowAction("Patch Manager: Registering Resource Locator", RegisterResourceLocator)); - } - else - { - SpaceWarp.API.Loading.Loading.GeneralLoadingActions.Insert(0, - () => new GenericFlowAction("Patch Manager: Registering Resource Locator", RegisterResourceLocator)); - } - } - - /// - public override void PreLoad() - { - var gameDataModsExists = Directory.Exists(Path.Combine(Paths.GameRootPath, "GameData/Mods")); - - // Go here instead so that the static constructor recognizes everything - var disabledPlugins = File.ReadAllText(SpaceWarp.Preload.API.CommonPaths.DisabledPluginsFilepath) - .Split(new[] { '\n' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToList(); - - var modFolders = Directory.GetDirectories(Paths.PluginPath, "*", SearchOption.AllDirectories) - .Where(dir => ShouldLoad(disabledPlugins, Path.Combine(dir, "swinfo.json"))) - .Select(x => ( - Folder: x, - Info: JsonConvert.DeserializeObject(File.ReadAllText(Path.Combine(x, "swinfo.json"))) - )) - .ToList(); - - if (gameDataModsExists) - { - modFolders.AddRange( - Directory - .GetDirectories(Path.Combine(Paths.GameRootPath, "GameData/Mods"), "*", SearchOption.AllDirectories) - .Where(dir => ShouldLoad(disabledPlugins, Path.Combine(dir, "swinfo.json"))) - .Select(x => ( - Folder: x, - Info: JsonConvert.DeserializeObject(File.ReadAllText(Path.Combine(x, "swinfo.json"))) - ))); - } - - var gameRoot = new DirectoryInfo(Paths.GameRootPath); - - var standalonePatches = Directory.EnumerateFiles( - Paths.PluginPath, - "*.patch", - SearchOption.AllDirectories - ) - .Where(x => NoSwinfo(new FileInfo(x).Directory, gameRoot)) - .Select(x => new FileInfo(x)) - .ToList(); - - if (gameDataModsExists) - { - standalonePatches.AddRange( - Directory.EnumerateFiles( - Path.Combine(Paths.GameRootPath, "GameData/Mods"), - "*.patch", - SearchOption.AllDirectories - ) - .Where(x => NoSwinfo(new FileInfo(x).Directory, gameRoot)) - .Select(x => new FileInfo(x)) - ); - } - - PatchingManager.GenerateUniverse(standalonePatches.Select(x => - x.Directory!.FullName - .MakeRelativePathTo(gameRoot.FullName) - .Replace("\\", "-") - ).ToHashSet()); - - foreach (var modFolder in modFolders) - { - Logging.LogInfo($"Loading patchers from {modFolder.Folder}"); - // var modName = Path.GetDirectoryName(modFolder); - PatchingManager.ImportModPatches(modFolder.Info.ModID, modFolder.Folder); - } - - foreach (var standalonePatch in standalonePatches) - { - PatchingManager.ImportSinglePatch(standalonePatch); - } - - PatchingManager.RegisterPatches(); - } - - /// - /// Registers the provider and locator for cached assets. - /// - private void RegisterResourceLocator(Action resolve, Action reject) - { - Addressables.ResourceManager.ResourceProviders.Add(new ArchiveResourceProvider()); - Locators.Register(new ArchiveResourceLocator()); - resolve(); - } - - /// - public override VisualElement GetDetails() - { - var foldout = new Foldout - { - text = "PatchManager.Core", - style = - { - display = DisplayStyle.Flex - }, - visible = true - }; - var text = new TextElement(); - text.text += $"Amount of loaded patchers: {PatchingManager.Patchers.Count}\n"; - text.text += $"Amount of loaded generators: {PatchingManager.Generators.Count}\n"; - text.text += $"Amount of loaded libraries: {PatchingManager.Universe.AllLibraries.Count}\n"; - if (_wasCacheInvalidated) - { - text.text += $"Total amount of patches: {PatchingManager.TotalPatchCount}\n"; - } - else - { - text.text += "Total amount of patches: Unknown (loaded from cache)\n"; - } - text.text += $"Total amount of errors: {PatchingManager.TotalErrorCount}\n"; - - text.text += "Patched labels:"; - foreach (var label in PatchingManager.Universe.LoadedLabels) - { - text.text += $"\n- {label}"; - } - - text.visible = true; - text.style.display = DisplayStyle.Flex; - foldout.Add(text); - - return foldout; - } - - /// - public override void BindConfiguration(IConfigFile modConfiguration) - { - _shouldAlwaysInvalidate = new(modConfiguration.Bind("Core", "Always Invalidate Cache", false, - "Should patch manager always invalidate its cache upon load")); - } - - /// - /// This is the current universe that patch manager is using (used for interop reasons) - /// - [PublicAPI] - public static Universe CurrentUniverse => PatchingManager.Universe; -} \ No newline at end of file diff --git a/src/PatchManager.Core/Flow/FlowAction.cs b/src/PatchManager.Core/Flow/FlowAction.cs deleted file mode 100644 index c870125..0000000 --- a/src/PatchManager.Core/Flow/FlowAction.cs +++ /dev/null @@ -1,29 +0,0 @@ -namespace PatchManager.Core.Flow; - -/// -/// Represents a general action to be executed during game loading. -/// -public class FlowAction : IAction -{ - private readonly Action> _doAction; - - /// - /// Creates a new instance of . - /// - /// - /// - public FlowAction(string name, Action> doAction) - { - Name = name; - _doAction = doAction; - } - - /// - public string Name { get; } - - /// - public void DoAction(Action resolve, Action reject) - { - _doAction(resolve, reject); - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Flow/FlowManager.cs b/src/PatchManager.Core/Flow/FlowManager.cs deleted file mode 100644 index fca5779..0000000 --- a/src/PatchManager.Core/Flow/FlowManager.cs +++ /dev/null @@ -1,49 +0,0 @@ -using KSP.Game.Flow; -using PatchManager.Shared; -using SpaceWarp.API.Loading; - -namespace PatchManager.Core.Flow; - -/// -/// Manages injection of game loading flow actions. -/// -public static class FlowManager -{ - private static readonly List Actions = new(); - - private static readonly Dictionary ActionsAfter = new(); - - /// - /// Registers an action to be executed at the end of game loading. - /// - /// Action to be executed. - public static void RegisterAction(IAction action) - { - Actions.Add(action); - } - - /// - /// Registers an action to be executed during game loading. - /// - /// Action to be executed. - /// Action name to insert the new action after, null to insert at the beginning. - public static void RegisterActionAfter(IAction action, string after) - { - ActionsAfter.Add(action, after); - } - - internal static void AddActionsToFlow(SequentialFlow loadingFlow) - { - foreach (var action in Actions) - { - loadingFlow.AddAction(new GenericFlowAction(action.Name, action.DoAction)); - Logging.LogDebug($"Registering flow action at the end: \"{action.Name}\""); - } - - foreach (var (action, after) in ActionsAfter) - { - SaveLoad.AddFlowActionToGameLoadAfter(new GenericFlowAction(action.Name, action.DoAction), after); - Logging.LogDebug($"Registering flow action \"{action.Name}\" after \"{after}\""); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Flow/IAction.cs b/src/PatchManager.Core/Flow/IAction.cs deleted file mode 100644 index 25ccf86..0000000 --- a/src/PatchManager.Core/Flow/IAction.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace PatchManager.Core.Flow; - -/// -/// Represents an action to be executed during game loading. -/// -public interface IAction -{ - /// - /// Name of the action. - /// - public string Name { get; } - - /// - /// Executes the action. - /// - /// Action to be executed on success. - /// Action to be executed on failure. - public void DoAction(Action resolve, Action reject); -} \ No newline at end of file diff --git a/src/PatchManager.Core/PatchManager.Core.csproj b/src/PatchManager.Core/PatchManager.Core.csproj deleted file mode 100644 index 731c350..0000000 --- a/src/PatchManager.Core/PatchManager.Core.csproj +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/src/PatchManager.Core/PatchManager.Core.csproj.DotSettings b/src/PatchManager.Core/PatchManager.Core.csproj.DotSettings deleted file mode 100644 index b5b235a..0000000 --- a/src/PatchManager.Core/PatchManager.Core.csproj.DotSettings +++ /dev/null @@ -1,2 +0,0 @@ - - Default \ No newline at end of file diff --git a/src/PatchManager.Core/Patches/Preload/AssetProviderPatch.cs b/src/PatchManager.Core/Patches/Preload/AssetProviderPatch.cs deleted file mode 100644 index 59f8582..0000000 --- a/src/PatchManager.Core/Patches/Preload/AssetProviderPatch.cs +++ /dev/null @@ -1,52 +0,0 @@ -using JetBrains.Annotations; -using KSP.Assets; -using KSP.Game; -using PatchManager.Core.Assets; -using Premonition.Core.Attributes; -using UnityEngine; -using UnityEngine.AddressableAssets; -using UnityEngine.ResourceManagement.AsyncOperations; -using UnityObject = UnityEngine.Object; - -namespace PatchManager.Core.Patches.Preload; - -[PremonitionAssembly("Assembly-CSharp")] -[PremonitionType("KSP.Assets.AssetProvider")] -internal static class AssetProviderPatch -{ - [PremonitionMethod("LoadByLabel")] - [PremonitionTrampoline] - [UsedImplicitly] - public static void LoadByLabel( - string label, - Action assetLoadCallback, - Action> resultCallback = null - ) where T : UnityObject - { - if (AssetProvider.IsComponent(typeof(T))) - { - Debug.LogError("AssetProvider cannot load components/monobehaviours in batch."); - return; - } - - LoadPatchedAssetsAsync(label, assetLoadCallback).Completed += results => - { - if (results.Status == AsyncOperationStatus.Succeeded) - { - resultCallback?.Invoke(results.Result); - return; - } - - Debug.LogError("AssetProvider unable to find assets with label '" + label + "'."); - resultCallback?.Invoke(null); - Addressables.Release((AsyncOperationHandle)results); - }; - } - - private static AsyncOperationHandle> LoadPatchedAssetsAsync( - string key, - Action assetLoadCallback - ) => Locators.LocateAll(key, out var patchedLocations) - ? Addressables.LoadAssetsAsync(patchedLocations, assetLoadCallback) - : GameManager.Instance.Assets.LoadAssetsAsync(key, assetLoadCallback); -} \ No newline at end of file diff --git a/src/PatchManager.Core/Patches/Runtime/ExternalAssetsPatch.cs b/src/PatchManager.Core/Patches/Runtime/ExternalAssetsPatch.cs deleted file mode 100644 index f3732ce..0000000 --- a/src/PatchManager.Core/Patches/Runtime/ExternalAssetsPatch.cs +++ /dev/null @@ -1,63 +0,0 @@ -using HarmonyLib; -using KSP.Assets; -using KSP.Game; -using PatchManager.Core.Assets; -using UnityEngine.ResourceManagement.ResourceLocations; - -namespace PatchManager.Core.Patches.Runtime; - -[HarmonyPatch] -internal static class ExternalAssetsPatch -{ - private static AssetProvider Assets => GameManager.Instance.Assets; - - [HarmonyPatch(typeof(AssetProvider), nameof(AssetProvider.LocateAssetInExternalData))] - [HarmonyPrefix] - // ReSharper disable once InconsistentNaming - private static bool LocateAssetInExternalData(object key, Type T, out IResourceLocation location, ref bool __result) - { - location = null; - - if (Locators.LocateAll(key.ToString(), out var patchedLocations)) - { - location = patchedLocations[0]; - __result = true; - return false; - } - - foreach (var registeredResourceLocator in Assets._registeredResourceLocators) - { - if (registeredResourceLocator.Locate(key, T, out var locations)) - { - location = locations[0]; - __result = true; - return false; - } - } - - return false; - } - - [HarmonyPatch(typeof(AssetProvider), nameof(AssetProvider.LocateAssetsInExternalData))] - [HarmonyPrefix] - // ReSharper disable once RedundantAssignment,InconsistentNaming - private static bool LocateAssetsInExternalData(object reference, ref List __result) - { - if (Locators.LocateAll(reference.ToString(), out var patchedLocations)) - { - __result = patchedLocations; - return false; - } - - __result = new List(); - foreach (var registeredResourceLocator in Assets._registeredResourceLocators) - { - if (registeredResourceLocator.Locate(reference, typeof(object), out var locations)) - { - __result.AddRange(locations); - } - } - - return false; - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Patches/Runtime/GameManagerPatch.cs b/src/PatchManager.Core/Patches/Runtime/GameManagerPatch.cs deleted file mode 100644 index 0df92ed..0000000 --- a/src/PatchManager.Core/Patches/Runtime/GameManagerPatch.cs +++ /dev/null @@ -1,20 +0,0 @@ -using HarmonyLib; -using KSP.Game; -using PatchManager.Core.Flow; - -namespace PatchManager.Core.Patches.Runtime; - -/// -/// Patches the method to add custom flow actions. -/// -[HarmonyPatch] -public static class GameManagerPatch -{ - [HarmonyPatch(typeof(GameManager), nameof(GameManager.StartBootstrap))] - [HarmonyPostfix] - // ReSharper disable once InconsistentNaming - private static void StartBootstrap_Postfix(GameManager __instance) - { - FlowManager.AddActionsToFlow(__instance.LoadingFlow); - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Patches/Runtime/LoadingBarPatch.cs b/src/PatchManager.Core/Patches/Runtime/LoadingBarPatch.cs deleted file mode 100644 index 78a6b9e..0000000 --- a/src/PatchManager.Core/Patches/Runtime/LoadingBarPatch.cs +++ /dev/null @@ -1,25 +0,0 @@ -using HarmonyLib; -using JetBrains.Annotations; -using PatchManager.Core.Assets; - -namespace PatchManager.Core.Patches.Runtime; - -[HarmonyPatch(typeof(LoadingBar))] -internal static class LoadingBarPatch -{ - public static bool InjectPatchManagerTips = false; - [HarmonyPrefix] - [HarmonyPatch(nameof(LoadingBar.ShuffleLoadingTip))] - [UsedImplicitly] - // ReSharper disable once InconsistentNaming - public static bool ShuffleLoadingTip(ref LoadingBar __instance) - { - if (!InjectPatchManagerTips) - return true; - __instance.tipsText.text = $"Patch Manager: {PatchingManager.TotalPatchCount} patches"; - if (PatchingManager.TotalErrorCount > 0) - __instance.tipsText.text += $", {PatchingManager.TotalErrorCount} errors"; - - return false; - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Utility/Hash.cs b/src/PatchManager.Core/Utility/Hash.cs deleted file mode 100644 index f0f02cd..0000000 --- a/src/PatchManager.Core/Utility/Hash.cs +++ /dev/null @@ -1,52 +0,0 @@ -using System.Security.Cryptography; -using System.Text; -using Newtonsoft.Json; - -namespace PatchManager.Core.Utility; - -/// -/// Hashing utility class. -/// -public static class Hash -{ - private static readonly MD5 Md5 = MD5.Create(); - - /// - /// Gets the MD5 hash of the input string. - /// - /// Input string. - /// MD5 hash of the input string. - public static string FromString(string input) - { - var hash = Md5.ComputeHash(Encoding.UTF8.GetBytes(input)); - return ByteArrayToString(hash); - } - - /// - /// Gets the MD5 hash of the input file. - /// - /// Path to the file. - /// MD5 hash of the input file. - public static string FromFile(string path) - { - var hash = Md5.ComputeHash(new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)); - return ByteArrayToString(hash); - } - - /// - /// Gets the MD5 hash of the input JSON-serializable object. - /// - /// JSON-serializable object. - /// MD5 hash of the JSON-serializable object. - public static string FromJsonObject(object input) - { - var json = JsonConvert.SerializeObject(input, Formatting.None); - return FromString(json); - } - - private static string ByteArrayToString(byte[] array) - { - var hashString = BitConverter.ToString(array).Replace("-", ""); - return hashString; - } -} \ No newline at end of file diff --git a/src/PatchManager.Core/Utility/Versions.cs b/src/PatchManager.Core/Utility/Versions.cs deleted file mode 100644 index 4dae7ad..0000000 --- a/src/PatchManager.Core/Utility/Versions.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System.Reflection; - -namespace PatchManager.Core.Utility; - -/// -/// Utility class containing versions of KSP 2 and PatchManager. -/// -public static class Versions -{ - /// - /// Currently running KSP 2 version. - /// - public static string Ksp2Version - { - get - { - var type = typeof(VersionID); - var field = type.GetField("VERSION_TEXT", BindingFlags.Static | BindingFlags.Public); - var value = field?.GetValue(null) as string; - return value; - } - } - - /// - /// Currently running PatchManager version. - /// - public static string PatchManagerVersion => Assembly.GetExecutingAssembly().GetName().Version.ToString(); -} \ No newline at end of file diff --git a/src/PatchManager.Generic/GenericModule.cs b/src/PatchManager.Generic/GenericModule.cs deleted file mode 100644 index 1e94534..0000000 --- a/src/PatchManager.Generic/GenericModule.cs +++ /dev/null @@ -1,10 +0,0 @@ -using PatchManager.Shared.Modules; - -namespace PatchManager.Generic; - -/// -/// Generic JSON patching module. -/// -public class GenericModule : BaseModule -{ -} \ No newline at end of file diff --git a/src/PatchManager.Generic/PatchManager.Generic.csproj b/src/PatchManager.Generic/PatchManager.Generic.csproj deleted file mode 100644 index f95ef0a..0000000 --- a/src/PatchManager.Generic/PatchManager.Generic.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/src/PatchManager.Generic/SassyPatching/Rulesets/JsonRuleset.cs b/src/PatchManager.Generic/SassyPatching/Rulesets/JsonRuleset.cs deleted file mode 100644 index 43f0af4..0000000 --- a/src/PatchManager.Generic/SassyPatching/Rulesets/JsonRuleset.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.NewAssets; -using PatchManager.SassyPatching.Selectables; - -namespace PatchManager.Generic.SassyPatching.Rulesets; - -/// -/// This is a generic json patching ruleset -/// -[PatcherRuleset("json")] -public class JsonRuleset : IPatcherRuleSet -{ - /// - public bool Matches(string label) - { - return true; - } - - /// - public ISelectable ConvertToSelectable(string type, string name, string jsonData) - { - return new JTokenSelectable(() => { }, JToken.Parse(jsonData), name, type); - } - - /// - public INewAsset CreateNew(List dataValues) - { - var label = dataValues[0].String; - var name = dataValues[1].String; - return new NewGenericAsset(label, name, new JTokenSelectable(() => { }, new JObject(), name, label)); - } -} \ No newline at end of file diff --git a/src/PatchManager.Missions/Builtins/MissionsBuiltins.cs b/src/PatchManager.Missions/Builtins/MissionsBuiltins.cs deleted file mode 100644 index 1a31613..0000000 --- a/src/PatchManager.Missions/Builtins/MissionsBuiltins.cs +++ /dev/null @@ -1,30 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Attributes; - -namespace PatchManager.Missions.Builtins; - -/// -/// Builtins for missions. -/// -[SassyLibrary("builtin","missions")] -[UsedImplicitly] -public class MissionsBuiltins -{ - /// - /// Gets the assembly-qualified type name of a property watcher. - /// - /// The name of the property watcher. - /// The assembly-qualified type name of the property watcher. - [SassyMethod("get-property-watcher"), UsedImplicitly] - public static string GetPropertyWatcher([SassyName("property-watcher-name")] string propertyWatcherName) => - MissionsTypes.PropertyWatchers[propertyWatcherName].AssemblyQualifiedName!; - - /// - /// Gets the assembly-qualified type name of a message. - /// - /// The name of the message. - /// The assembly-qualified type name of the message. - [SassyMethod("get-message"), UsedImplicitly] - public static string GetMessage([SassyName("message-name")] string messageName) => - MissionsTypes.Messages[messageName].AssemblyQualifiedName!; -} \ No newline at end of file diff --git a/src/PatchManager.Missions/MissionsModule.cs b/src/PatchManager.Missions/MissionsModule.cs deleted file mode 100644 index 270360e..0000000 --- a/src/PatchManager.Missions/MissionsModule.cs +++ /dev/null @@ -1,12 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.Shared.Modules; - -namespace PatchManager.Missions; - -/// -/// The missions module. -/// -[UsedImplicitly] -public class MissionsModule : BaseModule -{ -} \ No newline at end of file diff --git a/src/PatchManager.Missions/MissionsTypes.cs b/src/PatchManager.Missions/MissionsTypes.cs deleted file mode 100644 index acac9ac..0000000 --- a/src/PatchManager.Missions/MissionsTypes.cs +++ /dev/null @@ -1,54 +0,0 @@ -using KSP.Game.Missions; -using KSP.Messages; -using KSP.Messages.PropertyWatchers; - -namespace PatchManager.Missions; - -/// -/// This class is used to get all the types of the missions. -/// -public static class MissionsTypes -{ - /// - /// Dictionary of all the conditions. - /// - public static readonly Dictionary Conditions = new(); - /// - /// Dictionary of all the actions. - /// - public static readonly Dictionary Actions = new(); - /// - /// Dictionary of all the messages. - /// - public static readonly Dictionary Messages = new(); - /// - /// Dictionary of all the property watchers. - /// - public static readonly Dictionary PropertyWatchers = new(); - - static MissionsTypes() - { - foreach (var type in AppDomain.CurrentDomain.GetAssemblies().SelectMany(x => x.GetTypes()).Where(t => !t.IsAbstract)) - { - if (type.IsSubclassOf(typeof(Condition))) - { - Conditions.Add(type.Name,type); - } - - if (typeof(IMissionAction).IsAssignableFrom(type)) - { - Actions.Add(type.Name, type); - } - - if (type.IsSubclassOf(typeof(MessageCenterMessage))) - { - Messages.Add(type.Name, type); - } - - if (type.IsSubclassOf(typeof(PropertyWatcher))) - { - PropertyWatchers.Add(type.Name, type); - } - } - } -} \ No newline at end of file diff --git a/src/PatchManager.Missions/Modifiables/MissionModifiable.cs b/src/PatchManager.Missions/Modifiables/MissionModifiable.cs deleted file mode 100644 index edd4f60..0000000 --- a/src/PatchManager.Missions/Modifiables/MissionModifiable.cs +++ /dev/null @@ -1,39 +0,0 @@ -using PatchManager.Missions.Selectables; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Modifiables; - -namespace PatchManager.Missions.Modifiables; - -/// -/// Modifiable for . This is used to modify the mission object. -/// -public class MissionModifiable : JTokenModifiable -{ - /// - /// The that this modifiable is for. - /// - private readonly MissionSelectable _missionSelectable; - - /// - /// Creates a new for the given . - /// - /// The to create the modifiable for. - public MissionModifiable(MissionSelectable selectable) : base(selectable.MissionObject, selectable.SetModified) - { - _missionSelectable = selectable; - } - - /// - /// Sets the to be deleted if the is a deletion. - /// - /// The to set. - public override void Set(DataValue dataValue) - { - if (dataValue.IsDeletion) - { - _missionSelectable.SetDeleted(); - return; - } - base.Set(dataValue); - } -} \ No newline at end of file diff --git a/src/PatchManager.Missions/PatchManager.Missions.csproj b/src/PatchManager.Missions/PatchManager.Missions.csproj deleted file mode 100644 index 1a01286..0000000 --- a/src/PatchManager.Missions/PatchManager.Missions.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/PatchManager.Missions/Rulesets/MissionRuleset.cs b/src/PatchManager.Missions/Rulesets/MissionRuleset.cs deleted file mode 100644 index 2f1285e..0000000 --- a/src/PatchManager.Missions/Rulesets/MissionRuleset.cs +++ /dev/null @@ -1,35 +0,0 @@ -using KSP.Game.Missions.Definitions; -using Newtonsoft.Json.Linq; -using PatchManager.Missions.Selectables; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.NewAssets; - -namespace PatchManager.Missions.Rulesets; - -/// -/// Ruleset for the missions patcher. -/// -[PatcherRuleset("missions","missions")] -public class MissionRuleset : IPatcherRuleSet -{ - /// - public bool Matches(string label) => label == "missions"; - - /// - public ISelectable ConvertToSelectable(string type, string name, string jsonData) => - new MissionSelectable(JObject.Parse(jsonData)); - - /// - public INewAsset CreateNew(List dataValues) - { - var missionDataObject = new MissionData - { - ID = dataValues[0].String - }; - - return new NewGenericAsset("missions", dataValues[0].String, - new MissionSelectable(JObject.FromObject(missionDataObject))); - } -} \ No newline at end of file diff --git a/src/PatchManager.Missions/Selectables/ActionsSelectable.cs b/src/PatchManager.Missions/Selectables/ActionsSelectable.cs deleted file mode 100644 index 6d4d8ef..0000000 --- a/src/PatchManager.Missions/Selectables/ActionsSelectable.cs +++ /dev/null @@ -1,129 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Modifiables; -using PatchManager.SassyPatching.Selectables; - -namespace PatchManager.Missions.Selectables; - -/// -/// Selectable for the actions array of a mission. -/// -public sealed class ActionsSelectable : BaseSelectable -{ - /// - /// The mission selectable that this actions selectable belongs to. - /// - public MissionSelectable Selectable; - - /// - /// The actions array. - /// - public JArray Actions; - - private static string TrimTypeName(string typeName) - { - var comma = typeName.IndexOf(','); - if (comma != -1) - { - typeName = typeName[..comma]; - } - - var period = typeName.LastIndexOf('.'); - if (period != -1) - { - typeName = typeName[(period + 1)..]; - } - - return typeName; - } - - /// - /// Creates a new actions selectable. - /// - /// Mission selectable that this actions selectable belongs to. - /// Actions array. - public ActionsSelectable(MissionSelectable selectable, JArray actions) - { - Selectable = selectable; - Actions = actions; - Children = new List(); - Classes = new List(); - foreach (var action in actions) - { - var obj = (JObject)action; - var type = obj["$type"]!.Value()!; - var trimmedType = TrimTypeName(type); - Classes.Add(trimmedType); - Children.Add(new JTokenSelectable( - Selectable.SetModified, - obj, - token => TrimTypeName(((JObject)token)!.Value()!), - trimmedType - )); - } - } - - /// - public override List Children { get; } - - /// - public override string Name => "actions"; - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - foreach (var action in Actions) - { - var obj = (JObject)action; - var type = obj["$type"]!.Value()!; - var trimmedType = TrimTypeName(type); - if (trimmedType != @class) continue; - classValue = DataValue.FromJToken(action); - return true; - } - - classValue = DataValue.Null; - return false; - } - - /// - public override bool IsSameAs(ISelectable other) => - other is ActionsSelectable actionsSelectable && actionsSelectable.Actions == Actions; - - /// - public override IModifiable OpenModification() => new JTokenModifiable(Actions, Selectable.SetModified); - - /// - public override ISelectable AddElement(string elementType) - { - var actualType = MissionsTypes.Actions[elementType]; - var elementObject = new JObject() - { - ["$type"] = actualType.AssemblyQualifiedName - }; - foreach (var (key, value) in JObject.FromObject(Activator.CreateInstance(actualType))) - { - elementObject[key] = value; - } - - var selectable = new JTokenSelectable(Selectable.SetModified, elementObject, - token => TrimTypeName(((JObject)token)!.Value()!), elementType); - Children.Add(selectable); - Classes.Add(elementType); - Actions.Add(elementObject); - return selectable; - } - - /// - public override string Serialize() => Actions.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(Actions); - - /// - public override string ElementType => "actions"; -} \ No newline at end of file diff --git a/src/PatchManager.Missions/Selectables/ConditionSetSelectable.cs b/src/PatchManager.Missions/Selectables/ConditionSetSelectable.cs deleted file mode 100644 index d421aba..0000000 --- a/src/PatchManager.Missions/Selectables/ConditionSetSelectable.cs +++ /dev/null @@ -1,137 +0,0 @@ -using KSP.Game.Missions; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Modifiables; -using PatchManager.SassyPatching.Selectables; - -namespace PatchManager.Missions.Selectables; - -/// -/// Selectable for the condition set of a mission. -/// -public sealed class ConditionSetSelectable : BaseSelectable -{ - /// - /// The mission selectable that this condition set is a child of - /// - public MissionSelectable MissionSelectable; - - /// - /// The condition set that this selectable represents - /// - public JObject ConditionSet; - - /// - /// The children of this condition set - /// - private JArray _children; - - /// - /// Create a new condition set selectable - /// - /// Mission selectable that this condition set is a child of - /// The condition set that this selectable represents - public ConditionSetSelectable(MissionSelectable missionSelectable, JObject conditionSet) - { - MissionSelectable = missionSelectable; - ConditionSet = conditionSet; - _children = (JArray)conditionSet["Children"]!; - Children = new List(); - Classes = new List - { - "ConditionType", - "ConditionMode" - }; - // We aren't going to add the condition type as a child, it will still be editable tho - foreach (var child in _children) - { - var condition = (JObject)child; - var type = condition["ConditionType"]!.Value()!; - Classes.Add(type); - if (type == "ConditionSet") - { - Children.Add(new ConditionSetSelectable(missionSelectable, condition)); - } - else - { - Children.Add(new JTokenSelectable( - MissionSelectable.SetModified, - condition, - token => ((JObject)token)["ConditionType"]!.Value()!, - type - )); - } - } - } - - /// - public override List Children { get; } - - /// - public override string Name => "ConditionSet"; - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - foreach (var child in _children) - { - var condition = (JObject)child; - var type = condition["ConditionType"]!.Value()!; - if (type != @class) - continue; - classValue = DataValue.FromJToken(child); - } - - classValue = DataValue.Null; - return false; - } - - /// - public override bool IsSameAs(ISelectable other) => other is ConditionSetSelectable conditionSetSelectable && - conditionSetSelectable.ConditionSet == ConditionSet; - - /// - public override IModifiable OpenModification() => new JTokenModifiable(ConditionSet, MissionSelectable.SetModified); - - /// - public override ISelectable AddElement(string elementType) - { - var conditionType = MissionsTypes.Conditions[elementType]; - var conditionObject = new JObject() - { - ["$type"] = conditionType.AssemblyQualifiedName - }; - foreach (var (key, value) in JObject.FromObject(Activator.CreateInstance(conditionType))) - { - conditionObject[key] = value; - } - - _children.Add(conditionObject); - if (conditionType == typeof(ConditionSet)) - { - var selectable = new ConditionSetSelectable(MissionSelectable, conditionObject); - Children.Add(selectable); - return selectable; - } - else - { - var selectable = new JTokenSelectable(MissionSelectable.SetModified, conditionObject, - "scriptableCondition", "scriptableCondition"); - Children.Add(selectable); - return selectable; - } - } - - /// - public override string Serialize() => ConditionSet.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(ConditionSet); - - /// - public override string ElementType => "ConditionSet"; -} \ No newline at end of file diff --git a/src/PatchManager.Missions/Selectables/ContentBranchSelectable.cs b/src/PatchManager.Missions/Selectables/ContentBranchSelectable.cs deleted file mode 100644 index c12255b..0000000 --- a/src/PatchManager.Missions/Selectables/ContentBranchSelectable.cs +++ /dev/null @@ -1,82 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Modifiables; - -namespace PatchManager.Missions.Selectables; - -/// -/// A selectable for a content branch. -/// -public sealed class ContentBranchSelectable : BaseSelectable -{ - /// - /// The mission selectable that this content branch belongs to. - /// - public MissionSelectable Selectable; - - /// - /// The content branch that this selectable represents. - /// - public JObject ContentBranch; - - /// - /// The actions selectable that this content branch contains. - /// - private ActionsSelectable _actionsSelectable; - - /// - /// Creates a new content branch selectable. - /// - /// Mission selectable that this content branch belongs to. - /// Content branch that this selectable represents. - public ContentBranchSelectable(MissionSelectable selectable, JObject contentBranch) - { - Selectable = selectable; - ContentBranch = contentBranch; - Classes = new List { "actions" }; - Children = new List(); - _actionsSelectable = new ActionsSelectable(selectable, (JArray)contentBranch["actions"]!); - Children.Add(_actionsSelectable); - Classes.AddRange(_actionsSelectable.Classes); - Children.AddRange(_actionsSelectable.Children); - } - - /// - public override List Children { get; } - - /// - public override string Name => ContentBranch["ID"]!.Value()!; - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) => - _actionsSelectable.MatchesClass(@class, out classValue); - - /// - public override bool IsSameAs(ISelectable other) => other is ContentBranchSelectable contentBranchSelectable && - contentBranchSelectable.ContentBranch == ContentBranch; - - /// - public override IModifiable OpenModification() => new JTokenModifiable(ContentBranch, Selectable.SetModified); - - /// - public override ISelectable AddElement(string elementType) - { - var result = _actionsSelectable.AddElement(elementType); - Children.Add(result); - Classes.Add(elementType); - return result; - } - - /// - public override string Serialize() => ContentBranch.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(ContentBranch); - - /// - public override string ElementType => ContentBranch["ID"]!.Value()!; -} \ No newline at end of file diff --git a/src/PatchManager.Missions/Selectables/ContentBranchesSelectable.cs b/src/PatchManager.Missions/Selectables/ContentBranchesSelectable.cs deleted file mode 100644 index b6b78d8..0000000 --- a/src/PatchManager.Missions/Selectables/ContentBranchesSelectable.cs +++ /dev/null @@ -1,100 +0,0 @@ -using KSP.Game.Missions; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Modifiables; - -namespace PatchManager.Missions.Selectables; - -/// -/// Selectable for the ContentBranches of a Mission -/// -public sealed class ContentBranchesSelectable : BaseSelectable -{ - /// - /// The MissionSelectable this ContentBranchesSelectable belongs to - /// - public MissionSelectable Selectable; - - /// - /// The ContentBranches of the Mission - /// - public JArray ContentBranches; - - /// - /// Create a new ContentBranchesSelectable - /// - /// Mission selectable this ContentBranchesSelectable belongs to - /// Content branches of the mission - public ContentBranchesSelectable(MissionSelectable selectable, JArray contentBranches) - { - Selectable = selectable; - ContentBranches = contentBranches; - Children = new List(); - Classes = new List(); - foreach (var child in ContentBranches) - { - var obj = (JObject)child; - var id = obj["ID"]!.Value()!; - Classes.Add(id); - Children.Add(new ContentBranchSelectable(selectable,obj)); - } - } - - /// - public override List Children { get; } - - /// - public override string Name => "ContentBranches"; - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - foreach (var child in ContentBranches) - { - var obj = (JObject)child; - var id = obj["ID"]!.Value()!; - if (id != @class) - continue; - classValue = DataValue.FromJToken(obj); - return true; - } - - classValue = DataValue.Null; - return false; - } - - /// - public override bool IsSameAs(ISelectable other) => other is ContentBranchesSelectable contentBranchesSelectable && - contentBranchesSelectable.ContentBranches == ContentBranches; - - /// - public override IModifiable OpenModification() => new JTokenModifiable(ContentBranches, Selectable.SetModified); - - /// - public override ISelectable AddElement(string elementType) - { - var branch = new MissionContentBranch - { - ID = elementType - }; - var obj = JObject.FromObject(branch); - var selectable = new ContentBranchSelectable(Selectable, obj); - Children.Add(selectable); - Classes.Add(elementType); - ContentBranches.Add(obj); - return selectable; - } - - /// - public override string Serialize() => ContentBranches.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(ContentBranches); - - /// - public override string ElementType => "ContentBranches"; -} \ No newline at end of file diff --git a/src/PatchManager.Missions/Selectables/MissionRewardSelectable.cs b/src/PatchManager.Missions/Selectables/MissionRewardSelectable.cs deleted file mode 100644 index fb03f33..0000000 --- a/src/PatchManager.Missions/Selectables/MissionRewardSelectable.cs +++ /dev/null @@ -1,111 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Modifiables; -using PatchManager.SassyPatching.Selectables; - -namespace PatchManager.Missions.Selectables; - -/// -/// A selectable for a mission reward. -/// -public sealed class MissionRewardSelectable : BaseSelectable -{ - /// - /// The mission selectable this reward belongs to. - /// - public MissionSelectable MissionSelectable; - - /// - /// The mission reward. - /// - public JObject MissionReward; - - /// - /// The mission reward definitions. - /// - private JArray _missionRewardDefinitions; - - /// - /// Creates a new mission reward selectable. - /// - /// Mission selectable this reward belongs to. - /// Mission reward. - public MissionRewardSelectable(MissionSelectable missionSelectable, JObject missionReward) - { - MissionSelectable = missionSelectable; - MissionReward = missionReward; - _missionRewardDefinitions = (JArray)missionReward["MissionRewardDefinitions"]!; - Classes = new List(); - Children = new List(); - foreach (var child in _missionRewardDefinitions) - { - var obj = (JObject)child; - var name = obj["MissionRewardType"]!.Value()!; - Classes.Add(name); - Children.Add(new JTokenSelectable(MissionSelectable.SetModified, child, - token => ((JObject)token)["MissionRewardType"]!.Value(), name)); - } - } - - /// - public override List Children { get; } - - /// - public override string Name => "MissionReward"; - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - foreach (var child in _missionRewardDefinitions) - { - var obj = (JObject)child; - var name = obj["MissionRewardType"]!.Value()!; - if (name != @class) - { - continue; - } - - classValue = DataValue.FromJToken(obj); - return true; - } - - classValue = DataValue.Null; - return false; - } - - /// - public override bool IsSameAs(ISelectable other) => other is MissionRewardSelectable missionRewardSelectable && - missionRewardSelectable.MissionReward == MissionReward; - - /// - public override IModifiable OpenModification() => - new JTokenModifiable(MissionReward, MissionSelectable.SetModified); - - /// - public override ISelectable AddElement(string elementType) - { - var obj = new JObject - { - ["MissionRewardType"] = elementType - }; - Classes.Add(elementType); - var selectable = new JTokenSelectable(MissionSelectable.SetModified, obj, - token => ((JObject)token)["MissionRewardType"]!.Value(), elementType); - Children.Add(selectable); - _missionRewardDefinitions.Add(obj); - return selectable; - } - - /// - public override string Serialize() => MissionReward.ToString(); - - /// - public override DataValue GetValue() => DataValue.From(_missionRewardDefinitions); - - /// - public override string ElementType => "MissionReward"; -} \ No newline at end of file diff --git a/src/PatchManager.Missions/Selectables/MissionSelectable.cs b/src/PatchManager.Missions/Selectables/MissionSelectable.cs deleted file mode 100644 index bc79823..0000000 --- a/src/PatchManager.Missions/Selectables/MissionSelectable.cs +++ /dev/null @@ -1,109 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.Missions.Modifiables; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Selectables; - -namespace PatchManager.Missions.Selectables; - -/// -/// A selectable for the main body of a mission -/// -public sealed class MissionSelectable : BaseSelectable -{ -#pragma warning disable CS0414 // Field is assigned but its value is never used - private bool _modified; -#pragma warning restore CS0414 // Field is assigned but its value is never used - private bool _deleted; - - /// - /// Marks this part selectable as having been modified any level down - /// - public void SetModified() - { - _modified = true; - } - - /// - /// Marks this part as goneso - /// - public void SetDeleted() - { - SetModified(); - _deleted = true; - } - - /// - /// Creates a new mission selectable from a JObject - /// - /// The JObject to create the selectable from - public MissionSelectable(JObject missionObject) - { - MissionObject = missionObject; - Children = new List(); - Classes = new List(); - foreach (var child in missionObject) - { - Classes.Add(child.Key); - if (child.Key != "missionStages" && child.Key != "ContentBranches") - { - Children.Add(new JTokenSelectable(SetModified, child.Value, child.Key, child.Key)); - } - } - - var stages = (JArray)MissionObject["missionStages"]!; - Children.Add(new StagesSelectable(this, stages)); - if (missionObject.ContainsKey("ContentBranches")) - { - var branches = (JArray)MissionObject["ContentBranches"]!; - Children.Add(new ContentBranchesSelectable(this, branches)); - } - } - - /// - /// The JObject that this selectable represents - /// - public JObject MissionObject; - - /// - public override List Children { get; } - - /// - public override string Name => MissionObject["ID"]!.Value()!; - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - if (MissionObject.TryGetValue(@class, out var jToken)) - { - classValue = DataValue.FromJToken(jToken); - return true; - } - - classValue = DataValue.Null; - return false; - } - - /// - public override bool IsSameAs(ISelectable other) => - other is MissionSelectable selectable && selectable.MissionObject == MissionObject; - - /// - public override IModifiable OpenModification() => new MissionModifiable(this); - - /// - public override ISelectable AddElement(string elementType) => throw new Exception( - "You cannot add elements to the main body of the mission, try using ContentBranches, or missionStages for that"); - - /// - public override string Serialize() => _deleted ? "" : MissionObject.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(MissionObject); - - /// - public override string ElementType => "missions"; -} \ No newline at end of file diff --git a/src/PatchManager.Missions/Selectables/StageSelectable.cs b/src/PatchManager.Missions/Selectables/StageSelectable.cs deleted file mode 100644 index 3466df5..0000000 --- a/src/PatchManager.Missions/Selectables/StageSelectable.cs +++ /dev/null @@ -1,152 +0,0 @@ -using KSP.Game.Missions; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Modifiables; -using PatchManager.SassyPatching.Selectables; - -namespace PatchManager.Missions.Selectables; - -/// -/// Selectable for a stage in a mission. -/// -public sealed class StageSelectable : BaseSelectable -{ - /// - /// The mission selectable that this stage belongs to. - /// - public MissionSelectable MissionSelectable; - - /// - /// The stage object. - /// - public JObject StageObject; - - private int _conditionIndex = -1; - - /// - /// Create a new stage selectable. - /// - /// Mission selectable that this stage belongs to. - /// Stage object. - public StageSelectable(MissionSelectable missionSelectable, JObject stageObject) - { - MissionSelectable = missionSelectable; - StageObject = stageObject; - Children = new List(); - Classes = new List(); - foreach (var child in stageObject) - { - Classes.Add(child.Key); - if (child.Key != "scriptableCondition" && child.Key != "actions" && child.Key != "MissionReward") - { - Children.Add(new JTokenSelectable(MissionSelectable.SetModified, child.Value, child.Key, child.Key)); - } - } - - if (stageObject["scriptableCondition"].Type == JTokenType.Object) - { - if (((JObject)stageObject["scriptableCondition"]!)["ConditionType"]!.Value() == "ConditionSet") - { - _conditionIndex = Children.Count; - Children.Add( - new ConditionSetSelectable(missionSelectable, (JObject)stageObject["scriptableCondition"]!)); - } - else - { - _conditionIndex = Children.Count; - Children.Add(new JTokenSelectable(MissionSelectable.SetModified, stageObject["scriptableCondition"], - "scriptableCondition", "scriptableCondition")); - } - } - - if (stageObject.TryGetValue("MissionReward", out var value)) - { - Children.Add(new MissionRewardSelectable(MissionSelectable, (JObject)value!)); - } - - Children.Add(new ActionsSelectable(MissionSelectable, (JArray)stageObject["actions"]!)); - } - - /// - public override List Children { get; } - - /// - public override string Name => $"_{StageObject["StageID"]!.Value()}"; - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - if (StageObject.TryGetValue(@class, out var jToken)) - { - classValue = DataValue.FromJToken(jToken); - return true; - } - - classValue = DataValue.Null; - return false; - } - - /// - public override bool IsSameAs(ISelectable other) => - other is StageSelectable stageSelectable && stageSelectable.StageObject == StageObject; - - /// - public override IModifiable OpenModification() => new JTokenModifiable(StageObject, MissionSelectable.SetModified); - - /// - public override ISelectable AddElement(string elementType) - { - var conditionType = MissionsTypes.Conditions[elementType]; - // var conditionObject = JObject.FromObject(Activator.CreateInstance(conditionType)); - var conditionObject = new JObject(); - foreach (var (key, value) in JObject.FromObject(Activator.CreateInstance(conditionType))) - { - conditionObject[key] = value; - } - - StageObject["scriptableCondition"] = conditionObject; - if (conditionType == typeof(ConditionSet)) - { - var selectable = new ConditionSetSelectable(MissionSelectable, conditionObject); - if (_conditionIndex > 0) - { - return Children[_conditionIndex] = selectable; - } - - _conditionIndex = Children.Count; - Children.Add(selectable); - return selectable; - } - else - { - var selectable = new JTokenSelectable( - MissionSelectable.SetModified, - conditionObject, - "scriptableCondition", - "scriptableCondition" - ); - - if (_conditionIndex > 0) - { - return Children[_conditionIndex] = selectable; - } - - _conditionIndex = Children.Count; - Children.Add(selectable); - return selectable; - } - } - - /// - public override string Serialize() => StageObject.ToString(); - - /// - public override DataValue GetValue() => DataValue.From(StageObject); - - /// - public override string ElementType => $"_{StageObject["StageID"]!.Value()}"; -} \ No newline at end of file diff --git a/src/PatchManager.Missions/Selectables/StagesSelectable.cs b/src/PatchManager.Missions/Selectables/StagesSelectable.cs deleted file mode 100644 index 567df67..0000000 --- a/src/PatchManager.Missions/Selectables/StagesSelectable.cs +++ /dev/null @@ -1,101 +0,0 @@ -using KSP.Game.Missions.Definitions; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Modifiables; - -namespace PatchManager.Missions.Selectables; - -/// -/// Selectable for the stages of a mission. -/// -public sealed class StagesSelectable : BaseSelectable -{ - /// - /// The mission selectable this stage selectable belongs to. - /// - public MissionSelectable MissionSelectable; - - /// - /// The stages of the mission. - /// - public JArray Stages; - - /// - /// Creates a new stages selectable. - /// - /// Mission selectable this stage selectable belongs to. - /// The stages of the mission. - public StagesSelectable(MissionSelectable selectable, JArray stages) - { - MissionSelectable = selectable; - Stages = stages; - Children = new List(); - Classes = new List(); - foreach (var stage in stages) - { - var obj = (JObject)stage; - var id = obj["StageID"]!.Value(); - var idString = $"_{id}"; - Classes.Add(idString); - Children.Add(new StageSelectable(selectable, obj)); - } - } - - /// - public override List Children { get; } - - /// - public override string Name => "missionStages"; - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - var num = long.Parse(@class[1..]); - foreach (var stage in Stages) - { - var obj = (JObject)stage; - var id = obj["ID"]!.Value(); - if (id != num) continue; - classValue = DataValue.FromJToken(obj); - return true; - } - classValue = DataValue.Null; - return false; - } - - /// - public override bool IsSameAs(ISelectable other) => - other is StagesSelectable stagesSelectable && stagesSelectable.Stages == Stages; - - /// - public override IModifiable OpenModification() => new JTokenModifiable(Stages, MissionSelectable.SetModified); - - /// - public override ISelectable AddElement(string elementType) - { - var num = long.Parse(elementType[1..]); - var obj = new MissionStage - { - StageID = (int)num - }; - var stage = JObject.FromObject(obj); - Classes.Add(elementType); - var selectable = new StageSelectable(MissionSelectable, stage); - Children.Add(selectable); - Stages.Add(stage); - return selectable; - } - - /// - public override string Serialize() => Stages.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(Stages); - - /// - public override string ElementType => "missionStages"; -} \ No newline at end of file diff --git a/src/PatchManager.Parts/Attributes/ModuleDataAdapterAttribute.cs b/src/PatchManager.Parts/Attributes/ModuleDataAdapterAttribute.cs deleted file mode 100644 index 9955605..0000000 --- a/src/PatchManager.Parts/Attributes/ModuleDataAdapterAttribute.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace PatchManager.Parts.Attributes; - -/// -/// Types that take this attribute must inherit from (ISelectable) and must have a constructor that takes the following arguments -/// JObject - ModuleData.DataObject -/// ModuleSelectable - Module -/// -[AttributeUsage(AttributeTargets.Class)] -public class ModuleDataAdapterAttribute : Attribute -{ - /// - /// The types this adapter is used for - /// - public readonly Type[] ValidTypes; - /// - /// Mark this class as a custom module data adapter - /// - /// What data types it adapts - public ModuleDataAdapterAttribute(params Type[] validTypes) => ValidTypes = validTypes; -} \ No newline at end of file diff --git a/src/PatchManager.Parts/Builtins/PartsBuiltins.cs b/src/PatchManager.Parts/Builtins/PartsBuiltins.cs deleted file mode 100644 index 5d0a4e0..0000000 --- a/src/PatchManager.Parts/Builtins/PartsBuiltins.cs +++ /dev/null @@ -1,323 +0,0 @@ -using JetBrains.Annotations; -using KSP.IO; -using KSP.Sim.Definitions; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Attributes; - -namespace PatchManager.Parts.Builtins; - -/// -/// This library contains utilities for working with parts in Patch Manager -/// -[SassyLibrary("builtin","parts")] -[PublicAPI] -public class PartsBuiltins -{ - - /// - /// Finds a module in a part data object - /// - /// The part data object - /// The module name - /// The found module or a null value - [SassyMethod("find-module")] - public DataValue FindModule([SassyName("part-object")] Dictionary partObject, [SassyName("module-name")] string moduleName) - { - if (moduleName.StartsWith("PartComponent")) - moduleName = moduleName.Replace("PartComponent", ""); - var modules = partObject["serializedPartModules"].List.Select(x => x.Dictionary); - foreach (var module in modules) - { - if (module["Name"].String.Replace("PartComponent", "") == moduleName) - { - return module; - } - } - - return DataValue.Null; - } - - /// - /// Adds a module to a part data object - /// - /// The part data object - /// The module to add - /// The new part data object - [SassyMethod("add-module")] - public Dictionary AddModule([SassyName("part-object")] Dictionary partObject, Dictionary module) - { - var newObject = new Dictionary(partObject); - newObject["serializedPartModules"].List.Add(module); - return newObject; - } - - /// - /// Removes a module from a part data object - /// - /// The part data object - /// The name of the module to remove - /// The new part data object - [SassyMethod("remove-module")] - public Dictionary RemoveModule([SassyName("part-object")] Dictionary partObject, [SassyName("module-name")] string moduleName) - { - if (moduleName.StartsWith("PartComponent")) - moduleName = moduleName.Replace("PartComponent", ""); - var newObject = new Dictionary(partObject); - var index = -1; - var modules = partObject["serializedPartModules"].List.Select(x => x.Dictionary).ToList(); - for (var i = 0; i < modules.Count; i++) - { - if (modules[i]["Name"].String.Replace("PartComponent", "") != moduleName) - { - continue; - } - - index = i; - break; - } - - if (index >= 0) - { - newObject["serializedPartModules"].List.RemoveAt(index); - } - - return newObject; - } - - /// - /// Replaces a module in a part data object - /// - /// The part data object - /// The name of the module to replace - /// The new module - /// The new part data object - [SassyMethod("replace-module")] - public Dictionary ReplaceModule( - [SassyName("part-object")] Dictionary partObject, - [SassyName("module-name")] string moduleName, - Dictionary module - ) - { - if (moduleName.StartsWith("PartComponent")) - moduleName = moduleName.Replace("PartComponent", ""); - var newObject = new Dictionary(partObject); - var index = -1; - var modules = partObject["serializedPartModules"].List.Select(x => x.Dictionary).ToList(); - for (var i = 0; i < modules.Count; i++) - { - if (modules[i]["Name"].String.Replace("PartComponent", "") != moduleName) - { - continue; - } - - index = i; - break; - } - - if (index >= 0) - { - newObject["serializedPartModules"].List[index] = module; - } - else - { - newObject["serializedPartModules"].List.Add(module); - } - return newObject; - } - - /// - /// Creates a new module object - /// - /// The type of module to create - /// The new module object - /// If the module type is unknown - [SassyMethod("create-module")] - public Dictionary CreateModule(string type) - { - - if (!PartsUtilities.ComponentModules.TryGetValue(type, out var mod)) - { - throw new Exception($"Unknown part module {type}"); - } - var moduleObject = new JObject() - { - ["Name"] = mod.componentModule.Name, - ["ComponentType"] = mod.componentModule.AssemblyQualifiedName, - ["BehaviourType"] = mod.behaviour.AssemblyQualifiedName, - ["ModuleData"] = new JArray() - }; - return DataValue.FromJToken(moduleObject).Dictionary; - } - - - /// - /// Finds a module data object in a part module - /// - /// The part module - /// The name of the module data - /// - [SassyMethod("find-module-data")] - public DataValue FindModuleData([SassyName("part-module")] Dictionary partModule, [SassyName("module-data-name")] string moduleDataName) - { - var data = partModule["ModuleData"].List.Select(x => x.Dictionary); - foreach (var moduleData in data) - { - if (moduleData["Name"].String == moduleDataName) - { - return moduleData; - } - } - return DataValue.Null; - } - - /// - /// Adds a module data object to a part module - /// - /// The part module - /// The module data object - /// The new part module - [SassyMethod("add-module-data")] - public Dictionary AddModuleData([SassyName("part-module")] Dictionary partModule, [SassyName("module-data")] Dictionary moduleData) - { - var newObject = new Dictionary(partModule); - newObject["ModuleData"].List.Add(moduleData); - return newObject; - } - - /// - /// Removes a module data object from a part module - /// - /// The part module - /// The name of the module data object to remove - /// The new part module - [SassyMethod("remove-module-data")] - public Dictionary RemoveModuleData( - [SassyName("part-module")] Dictionary partModule, - [SassyName("module-data-name")] string moduleDataName - ) - { - var newObject = new Dictionary(partModule); - var index = -1; - var modules = partModule["ModuleData"].List.Select(x => x.Dictionary).ToList(); - for (var i = 0; i < modules.Count; i++) - { - if (modules[i]["Name"].String != moduleDataName) - { - continue; - } - - index = i; - break; - } - - if (index >= 0) - { - newObject["ModuleData"].List.RemoveAt(index); - } - - return newObject; - } - - /// - /// Replaces a module data object in a part module - /// - /// The part module - /// The name of the module data object to replace - /// The new module data object - /// The new part module - [SassyMethod("replace-module-data")] - public Dictionary ReplaceModuleData( - [SassyName("part-module")] Dictionary partModule, - [SassyName("module-data-name")] string moduleDataName, - [SassyName("module-data")] Dictionary moduleData - ) - { - var newObject = new Dictionary(partModule); - var index = -1; - var modules = partModule["ModuleData"].List.Select(x => x.Dictionary).ToList(); - for (var i = 0; i < modules.Count; i++) - { - if (modules[i]["Name"].String != moduleDataName) - { - continue; - } - - index = i; - break; - } - - if (index >= 0) - { - newObject["ModuleData"].List[index] = moduleData; - } - else - { - newObject["ModuleData"].List.Add(moduleData); - } - - return newObject; - } - - /// - /// Creates a new module data object - /// - /// The type of module data to create - /// The new module data object - /// If the module data type is unknown - [SassyMethod("create-module-data")] - public Dictionary CreateModuleData(string type) - { - if (!PartsUtilities.DataModules.TryGetValue(type, out var dataModuleType)) - { - throw new Exception($"Unknown data module {type}"); - } - - var instance = (ModuleData)Activator.CreateInstance(dataModuleType); - var dataObject = new JObject - { - ["$type"] = $"{dataModuleType.FullName}, {dataModuleType.Assembly.GetName().Name}" - }; - var otherObject = JObject.Parse(IOProvider.ToJson(instance)); - foreach (var prop in otherObject) - { - dataObject[prop.Key] = prop.Value; - } - var trueType = new JObject - { - ["Name"] = dataModuleType.Name, - ["ModuleType"] = instance.ModuleType.AssemblyQualifiedName, - ["DataType"] = instance.DataType.AssemblyQualifiedName, - ["Data"] = null, - ["DataObject"] = dataObject - }; - return DataValue.FromJToken(trueType).Dictionary; - } - - /// - /// Gets the data object from a module data object - /// - /// The module data object - /// The data object - [SassyMethod("get-data-object")] - public static Dictionary GetDataObject( - [SassyName("module-data")] Dictionary moduleData - ) => moduleData["DataObject"].Dictionary; - - /// - /// Sets the data object in a module data object - /// - /// The module data object - /// The data object - /// The new module data object - [SassyMethod("set-data-object")] - public static Dictionary SetDataObject( - [SassyName("module-data")] Dictionary moduleData, - [SassyName("data-object")] Dictionary dataObject - ) - { - var result = new Dictionary(moduleData); - result["DataObject"] = dataObject; - return result; - } -} \ No newline at end of file diff --git a/src/PatchManager.Parts/Modifiables/PartModifiable.cs b/src/PatchManager.Parts/Modifiables/PartModifiable.cs deleted file mode 100644 index 938169a..0000000 --- a/src/PatchManager.Parts/Modifiables/PartModifiable.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.Parts.Selectables; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Modifiables; -using Enumerable = UniLinq.Enumerable; - -namespace PatchManager.Parts.Modifiables; - -/// -/// Represents the modifiable state of a part_json file -/// -public sealed class PartModifiable : CustomJTokenModifiable -{ - private PartSelectable _selectable; - internal PartModifiable(PartSelectable selectable) : base(selectable.JObject["data"],selectable.SetModified) - { - _selectable = selectable; - } - - /// - public override DataValue GetFieldValue(string fieldName) - { - var repl = fieldName.Replace("PartComponent", ""); - if (JToken is not JObject jObject) - return DataValue.Null; - if (!jObject.ContainsKey("serializedPartModules")) - return DataValue.Null; - foreach (var module in jObject["serializedPartModules"]) - { - if (module is not JObject moduleObject) continue; - if (moduleObject.ContainsKey("Name") && ((string)moduleObject["Name"])!.Replace("PartComponent", "") == repl) - return DataValue.FromJToken(module); - } - - if (jObject.TryGetValue(fieldName, out var value)) - return DataValue.FromJToken(value); - - return DataValue.Null; - } - - /// - public override void Set(DataValue dataValue) - { - if (dataValue.IsDeletion) - { - _selectable.SetDeleted(); - } - base.Set(dataValue); - } -} \ No newline at end of file diff --git a/src/PatchManager.Parts/PartsModule.cs b/src/PatchManager.Parts/PartsModule.cs deleted file mode 100644 index 4f77b1b..0000000 --- a/src/PatchManager.Parts/PartsModule.cs +++ /dev/null @@ -1,22 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.Parts.Patchers; -using PatchManager.Shared.Modules; -using SpaceWarp.API.Loading; - -namespace PatchManager.Parts; - -/// -/// Part patching module. -/// -[UsedImplicitly] -public class PartsModule : BaseModule -{ - /// - /// Initialize the module - /// - public override void Init() - { - PartsUtilities.GrabModuleDataAdapters(); - SaveLoad.AddFlowActionToCampaignLoadAfter("Parsing parts text assets"); - } -} \ No newline at end of file diff --git a/src/PatchManager.Parts/PartsUtilities.cs b/src/PatchManager.Parts/PartsUtilities.cs deleted file mode 100644 index 75701c9..0000000 --- a/src/PatchManager.Parts/PartsUtilities.cs +++ /dev/null @@ -1,123 +0,0 @@ -using KSP.Sim.Definitions; -using KSP.Sim.impl; -using PatchManager.Parts.Attributes; -using PatchManager.SassyPatching.Interfaces; - -namespace PatchManager.Parts; - -/// -/// Utilities for parts patching. -/// -public static class PartsUtilities -{ - private static Dictionary _componentModules; - - private static void BuildComponentModuleDictionary() - { - _componentModules = new(); - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - foreach (var type in assembly.GetTypes().Where(type => !type.IsAbstract).Where(type => type.IsSubclassOf(typeof(PartComponentModule)))) - { - try - { - var mod = (PartComponentModule)Activator.CreateInstance(type); - var behaviour = mod.PartBehaviourModuleType; - var tuple = (type, behaviour); - var name1 = type.Name; - var name2 = name1.Replace("PartComponent", ""); - _componentModules[name1] = tuple; - if (!name1.Equals(name2)) - { - _componentModules[name2] = tuple; - } - } - catch - { - //ignored - } - } - } - } - - internal static IReadOnlyDictionary ComponentModules - { - get - { - if (_componentModules == null) - { - BuildComponentModuleDictionary(); - } - - return _componentModules; - } - } - - - private static Dictionary _dataModules; - - private static void BuildDataModuleDictionary() - { - _dataModules = new(); - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - foreach (var type in assembly.GetTypes().Where(type => !type.IsAbstract) - .Where(type => type.IsSubclassOf(typeof(ModuleData)))) - { - var name1 = type.Name; - var name2 = name1.Replace("Data_", ""); - _dataModules[name1] = type; - if (!name1.Equals(name2)) - { - _dataModules[name2] = type; - } - } - } - } - - internal static IReadOnlyDictionary DataModules - { - get - { - if (_dataModules == null) - { - BuildDataModuleDictionary(); - } - - return _dataModules; - } - } - - internal static readonly Dictionary ModuleDataAdapters = new(); - - internal static void GrabModuleDataAdapters() - { - foreach (var type in AppDomain.CurrentDomain.GetAssemblies() - .SelectMany(x => x.GetTypes()) - .Where(x => x.GetCustomAttributes(typeof(ModuleDataAdapterAttribute), - false) - .Any()) - .Select(x => (type: x, attr: (ModuleDataAdapterAttribute)x.GetCustomAttributes(typeof(ModuleDataAdapterAttribute), - false) - .FirstOrDefault()))) - { - foreach (var dataType in type.attr.ValidTypes) - { - ModuleDataAdapters[dataType] = type.type; - } - } - } - - /// - /// Registers a module data adapter for the given types - /// - /// The types that this adapter is valid for - /// The type of the adapter - public static void RegisterModuleDataAdapter(params Type[] validTargets) where T : ISelectable - { - foreach (var type in validTargets) - { - ModuleDataAdapters[type] = typeof(T); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.Parts/PatchManager.Parts.csproj b/src/PatchManager.Parts/PatchManager.Parts.csproj deleted file mode 100644 index bbb14ea..0000000 --- a/src/PatchManager.Parts/PatchManager.Parts.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/PatchManager.Parts/Patchers/OABUtilsPatcher.cs b/src/PatchManager.Parts/Patchers/OABUtilsPatcher.cs deleted file mode 100644 index 164438a..0000000 --- a/src/PatchManager.Parts/Patchers/OABUtilsPatcher.cs +++ /dev/null @@ -1,33 +0,0 @@ -using HarmonyLib; -using KSP.OAB; - -namespace PatchManager.Parts.Patchers; - -[HarmonyPatch] -internal class OabUtilsPatcher -{ - /// - /// This is a map of part names to icon names. It is populated by the PartDataDeserializePatcher. - /// - internal static Dictionary PartIconMap { get; } = new(); - - /// - /// This patch is used to override the icon name for a part. - /// - /// Part name - /// The icon name to return. - /// True if the original method should be called, false otherwise. - [HarmonyPrefix] - [HarmonyPatch(typeof(Utils), nameof(Utils.GetPartIconNameFromPartName))] - // ReSharper disable once InconsistentNaming - internal static bool Utils_GetPartIconNameFromPartName(string partName, ref string __result) - { - if (PartIconMap.TryGetValue(partName, out var iconName)) - { - __result = iconName; - return false; - } - - return true; - } -} \ No newline at end of file diff --git a/src/PatchManager.Parts/Patchers/PartDataDeserializePatcher.cs b/src/PatchManager.Parts/Patchers/PartDataDeserializePatcher.cs deleted file mode 100644 index 3f4c647..0000000 --- a/src/PatchManager.Parts/Patchers/PartDataDeserializePatcher.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Text.RegularExpressions; -using HarmonyLib; -using KSP.Sim.Definitions; - -namespace PatchManager.Parts.Patchers; - -[HarmonyPatch] -internal static class PartDataDeserializePatcher -{ - [HarmonyPostfix] - [HarmonyPatch(typeof(PartCore), nameof(PartCore.UpgradeAndRead))] - // ReSharper disable once InconsistentNaming - internal static void PartCore_UpgradeAndRead(string rawFileData, ref PartCore __result) - { - var prefabAddress = Regex.Match(rawFileData, "\"PrefabAddress\":\\s*\"([^\"]*)\"").Groups[1].Value; - if (!string.IsNullOrEmpty(prefabAddress)) - { - PartModuleLoadPatcher.PartPrefabMap[__result.data.partName] = prefabAddress; - } - - var iconAddress = Regex.Match(rawFileData, "\"IconAddress\":\\s*\"([^\"]*)\"").Groups[1].Value; - if (!string.IsNullOrEmpty(iconAddress)) - { - OabUtilsPatcher.PartIconMap[__result.data.partName] = iconAddress; - } - } -} \ No newline at end of file diff --git a/src/PatchManager.Parts/Patchers/PartModuleLoadPatcher.cs b/src/PatchManager.Parts/Patchers/PartModuleLoadPatcher.cs deleted file mode 100644 index 9dd10a0..0000000 --- a/src/PatchManager.Parts/Patchers/PartModuleLoadPatcher.cs +++ /dev/null @@ -1,183 +0,0 @@ -using System.Reflection; -using HarmonyLib; -using KSP.Game; -using KSP.OAB; -using KSP.Sim; -using KSP.Sim.Definitions; -using KSP.Sim.impl; -using PatchManager.Shared; -using UnityEngine; -using Object = UnityEngine.Object; - -namespace PatchManager.Parts.Patchers; - -[HarmonyPatch] -internal static class PartModuleLoadPatcher -{ - /// - /// This is a map of part names to prefab names. It is populated by the PartDataDeserializePatcher. - /// - internal static Dictionary PartPrefabMap { get; } = new(); - - [HarmonyPrefix] - [HarmonyPatch(typeof(ObjectAssemblyPartTracker), nameof(ObjectAssemblyPartTracker.OnPartPrefabLoaded))] - internal static void ApplyOnGameObjectOAB(IObjectAssemblyAvailablePart obj, ref GameObject prefab) - { - ApplyOnGameObject(ref prefab, obj.PartData); - } - - [HarmonyPostfix] - [HarmonyPatch(typeof(SimulationObjectView), nameof(SimulationObjectView.InitializeView))] - internal static void ApplyOnGameObjectFlight( - ref GameObject instance, - IUniverseView universe, - SimulationObjectModel model - ) - { - if (!model.IsPart) - { - return; - } - - ApplyOnGameObject(ref instance, model.Part.PartData); - } - - private static void ApplyOnGameObject(ref GameObject gameObject, PartData partData) - { - var obj = gameObject; - - if (PartPrefabMap.TryGetValue(partData.partName, out var prefabName)) - { - var prefab = GameManager.Instance.Assets.LoadAssetAsync(prefabName).WaitForCompletion(); - obj = Object.Instantiate(prefab); - } - - foreach (var module in partData.serializedPartModules) - { - var behaviourType = module.BehaviourType; - // Debug.Log($"ApplyOnGameObject - {partData.partName} testing {behaviourType.FullName}"); - if (obj.GetComponent(behaviourType) != null) - { - continue; - } - - // Debug.Log($"ApplyOnGameObject - {partData.partName} adding {behaviourType.FullName}"); - var instance = obj.AddComponent(behaviourType); - Logging.LogInfo($"Attempting to setup serialized fields on {partData.partName} of type {behaviourType}"); - foreach (var field in behaviourType.GetFields(BindingFlags.Instance | BindingFlags.NonPublic) - .Concat(behaviourType.GetFields(BindingFlags.Public | BindingFlags.Instance))) - { - // Logging.LogInfo($"Found field: {field.Name} of type {field.FieldType}"); - if (!field.GetCustomAttributes(typeof(SerializeField), false).Any()) - { - continue; - } - - // Logging.LogInfo($"Field has SerializeField attribute"); - if (!field.FieldType.IsSubclassOf(typeof(ModuleData))) - { - continue; - } - - // Logging.LogInfo($"Field type {field.FieldType} is subclass of ModuleData, setting value"); - var data = module.ModuleData.FirstOrDefault(x => x.DataObject.GetType() == field.FieldType); - data.DataObject?.RebuildDataContext(); - field.SetValue(instance, data.DataObject); - } - } - - foreach (var component in obj.GetComponents()) - { - // Debug.Log($"ApplyOnGameObject - {partData.partName} checking {component.GetType().FullName}"); - var t = component.GetType(); - if (partData.serializedPartModules.All(x => x.BehaviourType != t)) - { - // Debug.Log($"ApplyOnGameObject - {partData.partName} removing {component.GetType().FullName}"); - Object.Destroy(component); - } - } - - gameObject = obj; - } - - [HarmonyPrefix] - [HarmonyPatch(typeof(PartComponent), nameof(PartComponent.SetDefinition))] - internal static void SetDefinition(object definitionData) - { - if (definitionData is PartDefinition partDefinition) - { - var name = partDefinition.Properties.partName; - var def = GameManager.Instance.Game.Parts.Get(name); - for (var i = partDefinition.Modules.Count - 1; i >= 0; i--) - { - var i2 = i; - if (def.data.serializedPartModules.All(x => x.Name != partDefinition.Modules[i2].Name)) - { - partDefinition.Modules.RemoveAt(i); - } - } - - foreach (var mod in def.data.serializedPartModules) - { - if (partDefinition.Modules.All(x => x.Name != mod.Name)) - { - partDefinition.Modules.Add(mod); - } - } - } - } - // [HarmonyPrefix] - // [HarmonyPatch(typeof(SaveLoadManager), nameof(SaveLoadManager.PrivateLoadCommon))] - // internal static void LoadCommon( - // LoadOrSaveCampaignTicket loadOrSaveCampaignTicket, - // LoadGameData loadGameData, - // SequentialFlow loadingFlow, - // OnLoadOrSaveCampaignFinishedCallback onLoadOrSaveCampaignFinishedCallback) - // { - // void UpdateVessels(Action resolve, Action reject) - // { - // foreach (var vessel in loadGameData.SavedGame.Vessels) - // { - // // Lets change only a few things - // // Add modules, change resource containers - // foreach (var part in vessel.parts) - // { - // var name = part.partName; - // var def = GameManager.Instance.Game.Parts.Get(name); - // for (var i = part.PartModulesState.Count - 1; i >= 0; i--) - // { - // var i2 = i; - // if (def.data.serializedPartModules.All(x => x.Name != part.PartModulesState[i2].Name)) - // { - // part.PartModulesState.RemoveAt(i); - // } - // } - // - // foreach (var mod in def.data.serializedPartModules) - // { - // if (part.PartModulesState.All(x => x.Name != mod.Name)) - // { - // part.PartModulesState.Add(mod); - // } - // } - // - // foreach (var resource in def.data.resourceContainers) - // { - // if (!part.partState.resources.ContainsKey(resource.name)) - // { - // part.partState.resources[resource.name] = new ContainedResourceState - // { - // name = resource.name, - // storedUnits = resource.initialUnits, - // capacityUnits = resource.capacityUnits - // }; - // } - // } - // } - // } - // resolve(); - // } - // loadingFlow.AddAction(new GenericFlowAction("Updating serialized vessels...", UpdateVessels)); - // } - -} \ No newline at end of file diff --git a/src/PatchManager.Parts/Patchers/UpdateSavedVesselPartDefinitions.cs b/src/PatchManager.Parts/Patchers/UpdateSavedVesselPartDefinitions.cs deleted file mode 100644 index 0ece3b6..0000000 --- a/src/PatchManager.Parts/Patchers/UpdateSavedVesselPartDefinitions.cs +++ /dev/null @@ -1,82 +0,0 @@ -using KSP.Game; -using KSP.Game.Flow; -using KSP.Game.Load; -using KSP.Sim.State; -using PatchManager.Shared; - -namespace PatchManager.Parts.Patchers; - -internal class UpdateSavedVesselPartDefinitions : FlowAction -{ - private LoadGameData _loadGameData; - - public UpdateSavedVesselPartDefinitions(LoadGameData loadGameData) : base("Updating saved vessel part definitions") - { - _loadGameData = loadGameData; - } - public override void DoAction(Action resolve, Action reject) - { - if (_loadGameData.SavedGame.Vessels == null) - { - resolve(); - return; - } - List toRemove = new(); - int idx = 0; - foreach (var vessel in _loadGameData.SavedGame.Vessels) - { - // Lets change only a few things - // Add modules, change resource containers - foreach (var part in vessel.parts) - { - var name = part.partName; - var def = GameManager.Instance.Game.Parts.Get(name); - if (def == null) - { - Logging.LogWarning($"Invalid part {name} found on vessel {vessel.AssemblyDefinition.assemblyName}, removing vessel from save file\n"); - toRemove.Add(idx); - break; - } - for (var i = part.PartModulesState.Count - 1; i >= 0; i--) - { - var i2 = i; - if (def.data.serializedPartModules.All(x => x.Name != part.PartModulesState[i2].Name)) - { - part.PartModulesState.RemoveAt(i); - } - } - - foreach (var mod in def.data.serializedPartModules) - { - if (part.PartModulesState.All(x => x.Name != mod.Name)) - { - part.PartModulesState.Add(mod); - } - } - - foreach (var resource in def.data.resourceContainers) - { - if (!part.partState.resources.ContainsKey(resource.name)) - { - part.partState.resources[resource.name] = new ContainedResourceState - { - name = resource.name, - storedUnits = resource.initialUnits, - capacityUnits = resource.capacityUnits - }; - } - } - } - idx += 1; - } - - toRemove.Reverse(); - var vesselList = _loadGameData.SavedGame.Vessels.ToList(); - foreach (var removal in toRemove) - { - vesselList.RemoveAt(removal); - } - _loadGameData.SavedGame.Vessels = vesselList.ToArray(); - resolve(); - } -} \ No newline at end of file diff --git a/src/PatchManager.Parts/Rulesets/PartsRuleset.cs b/src/PatchManager.Parts/Rulesets/PartsRuleset.cs deleted file mode 100644 index a738426..0000000 --- a/src/PatchManager.Parts/Rulesets/PartsRuleset.cs +++ /dev/null @@ -1,109 +0,0 @@ -using KSP.Game; -using KSP.IO; -using KSP.OAB; -using KSP.Sim; -using KSP.Sim.Definitions; -using KSP.Sim.ResourceSystem; -using Newtonsoft.Json.Linq; -using PatchManager.Parts.Selectables; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.NewAssets; -using UnityEngine; - -namespace PatchManager.Parts.Rulesets; - -/// -/// The `:parts` ruleset used by sassy patching -/// -[PatcherRuleset("parts", "parts_data")] -public class PartsRuleset : IPatcherRuleSet -{ - /// - public bool Matches(string label) => label == "parts_data"; - - /// - /// Converts the part json to an ISelectable following this ruleset - /// - /// - /// The name of the file (unused) - /// The part json - /// An ISelectable that follows the part ruleset - public ISelectable ConvertToSelectable(string type, string name, string jsonData) - { - return new PartSelectable(jsonData); - } - /// - /// - /// Create a new part asset - /// - /// The arguments for the part asset, only one argument: name - /// The part asset creator - public INewAsset CreateNew(List dataValues) - { - var name = dataValues[0].String; - var internalPartData = new PartData - { - partName = name, - angularDrag = 0, - coMassOffset = Vector3.zero, - coPressureOffset = Vector3.zero, - mass = 0, - maximumDrag = 0, - maxTemp = 0, - author = "", - bodyLiftOnlyUnattachedLift = false, - bodyLiftOnlyAttachName = "", - buoyancy = 0, - buoyancyUseSine = false, - breakingForce = 0, - breakingTorque = 0, - category = PartCategories.none, - family = "", - coBuoyancy = Vector3.zero, - coDisplacement = Vector3.zero, - oabEditorCategory = OABEditorPartCategory.NONE, - partType = AssemblyPartTypeFilter.Rocket, - cost = 0, - crashTolerance = 0, - crewCapacity = 0, - emissiveConstant = 0, - explosionPotential = 0, - fuelCrossFeed = false, - heatConductivity = 0, - inverseStageCarryover = false, - isCompound = false, - maxLength = 0, - radiatorHeadroom = 0, - radiatorMax = 0, - physicsMode = PartPhysicsModes.None, - sizeCategory = MetaAssemblySizeFilterType.XS, - skinMassPerArea = 0, - skinMaxTemp = 0, - skinInternalConductionMult = 0, - stageOffset = 0, - stageType = AssemblyPartStageType.None, - tags = "", - stagingIconAssetAddress = "", - attachRules = AttachRules.Defaults(), - attachNodes = new List(), - resourceContainers = new List(), - resourceCosts = new List(), - serializedPartModules = new List(), - resourceSummary = new SerializedResourceInfo(), - PAMModuleSortOverride = new List(), - PAMModuleVisualsOverride = new List(), - AllowKinematicPhysicsIfIntersectTerrain = false - }; - var internalJson = IOProvider.ToJson(internalPartData); - var internalJObject = JObject.Parse(internalJson); - var externalJObject = new JObject - { - ["version"] = "0.3", - ["useExternalData"] = false, - ["data"] = internalJObject - }; - return new NewGenericAsset("parts_data", name, new PartSelectable(externalJObject.ToString())); - } -} \ No newline at end of file diff --git a/src/PatchManager.Parts/Selectables/DataEngineSelectable.cs b/src/PatchManager.Parts/Selectables/DataEngineSelectable.cs deleted file mode 100644 index 471029f..0000000 --- a/src/PatchManager.Parts/Selectables/DataEngineSelectable.cs +++ /dev/null @@ -1,134 +0,0 @@ -using JetBrains.Annotations; -using KSP.Modules; -using Newtonsoft.Json.Linq; -using PatchManager.Parts.Attributes; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Modifiables; -using PatchManager.SassyPatching.Selectables; - -namespace PatchManager.Parts.Selectables; - -/// -/// Represents a selectable for the selection and transformation of Data_Engine -/// -[ModuleDataAdapter(typeof(Data_Engine))] -[UsedImplicitly] -public sealed class DataEngineSelectable : BaseSelectable -{ - /// - /// The serialized data for this selectable - /// - public readonly JObject SerializedData; - - /// - /// The part selectable that owns this selectable - /// - public readonly PartSelectable Selectable; - - /// - /// Initialize the selectable - /// - /// Module data - /// Module selectable - public DataEngineSelectable(JObject moduleData, ModuleSelectable moduleSelectable) - { - SerializedData = (JObject)moduleData["DataObject"]; - Name = "Data_Engine"; - Selectable = moduleSelectable.Selectable; - ElementType = moduleData["Name"].Value(); - Classes = new(); - Children = new(); - foreach (var field in SerializedData) - { - Classes.Add(field.Key); - if (field.Value.Type == JTokenType.Object) - { - Children.Add(new JTokenSelectable(Selectable.SetModified, field.Value, field.Key, field.Key)); - } - } - - var index = 0; - List removals = new(); - foreach (var jToken in (JArray)SerializedData["engineModes"]) - { - var currentIdx = index++; - if (jToken.Type is JTokenType.Null or JTokenType.None) - { - removals.Add(currentIdx); - continue; - } - var mode = (JObject)jToken; - Classes.Add(mode["engineID"].Value()); - Children.Add(new JTokenSelectable(Selectable.SetModified,mode,m => m["engineID"].Value(),"engine_mode")); - } - - removals.Reverse(); - foreach (var idx in removals) - ((JArray)SerializedData["engineModes"])[idx].Remove(); - } - - /// - public override List Children { get; } - - /// - public override string Name { get; } - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - if (SerializedData.TryGetValue(@class, out var value)) - { - classValue = DataValue.FromJToken(value); - return true; - } - - foreach (var jToken in (JArray)SerializedData["engineModes"]) - { - var mode = (JObject)jToken; - if (mode["engineID"].Value() != @class) - { - continue; - } - - classValue = DataValue.FromJToken(mode); - return true; - } - - classValue = DataValue.Null; - return false; - } - - /// - public override bool IsSameAs(ISelectable other) => - (other is DataEngineSelectable dataEngineSelectable) && - SerializedData == dataEngineSelectable.SerializedData; - - /// - public override IModifiable OpenModification() => new JTokenModifiable(SerializedData, Selectable.SetModified); - - /// - public override ISelectable AddElement(string elementType) - { - var engineModeData = new Data_Engine.EngineMode() - { - engineID = elementType - }; - var json = JObject.FromObject(engineModeData); - ((JArray)SerializedData["engineModes"]).Add(json); - return new JTokenSelectable(Selectable.SetModified, json, mode => mode["engineID"].Value(), - "engine_mode"); - } - - /// - public override string Serialize() => SerializedData.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(SerializedData); - - /// - public override string ElementType { get; } -} \ No newline at end of file diff --git a/src/PatchManager.Parts/Selectables/ModuleSelectable.cs b/src/PatchManager.Parts/Selectables/ModuleSelectable.cs deleted file mode 100644 index 633bfd5..0000000 --- a/src/PatchManager.Parts/Selectables/ModuleSelectable.cs +++ /dev/null @@ -1,135 +0,0 @@ -using KSP.IO; -using KSP.Sim.Definitions; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Modifiables; -using PatchManager.SassyPatching.Selectables; - -namespace PatchManager.Parts.Selectables; - -/// -/// Represents the selectable data in a part module; -/// -public sealed class ModuleSelectable : BaseSelectable -{ - /// - /// The serialized data for this selectable - /// - public readonly JToken SerializedData; - - /// - /// The part selectable that owns this selectable - /// - public readonly PartSelectable Selectable; - - private Dictionary _dataIndices; - - /// - public ModuleSelectable(JToken token, PartSelectable selectable) - { - SerializedData = token; - Selectable = selectable; - _dataIndices = new Dictionary(); - ElementType = ((string)token["Name"]).Replace("PartComponent", ""); - Name = ElementType; - Classes = new(); - Children = new(); - Classes.Add("ModuleData"); - // Now we go down the list in the data type - var data = (JArray)token["ModuleData"]; - var index = 0; - foreach (var moduleData in data) - { - _dataIndices[moduleData["Name"].Value()] = index++; - Classes.Add(moduleData["Name"].Value()); - // Where we are going to have to add children ree - // TODO: Add a specialization for ModuleEngine - Children.Add(GetSelectable((JObject)moduleData)); - } - } - - private ISelectable GetSelectable(JObject moduleData) - { - var type = Type.GetType(moduleData["DataType"].Value()); - if (type != null && PartsUtilities.ModuleDataAdapters.TryGetValue(type, out var adapterType)) - { - return (ISelectable)Activator.CreateInstance(adapterType, moduleData, this); - } - return new JTokenSelectable(Selectable.SetModified, moduleData["DataObject"], moduleData["Name"].Value()); - } - - /// - public override List Children { get; } - - /// - public override string Name { get; } - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) { - - if (_dataIndices.TryGetValue(@class.Replace("PartComponent", ""), out var index)) - { - classValue = DataValue.FromJToken(SerializedData["ModuleData"][index]["DataObject"]); - return true; - } - classValue = null; - return false; - } - - /// - public override string ElementType { get; } - - - - /// - public override bool IsSameAs(ISelectable other) => - other is ModuleSelectable moduleSelectable && moduleSelectable.SerializedData == SerializedData; - - /// - public override IModifiable OpenModification() - { - return new JTokenModifiable(SerializedData, Selectable.SetModified); - } - - /// - public override ISelectable AddElement(string elementType) - { - if (!PartsUtilities.DataModules.TryGetValue(elementType, out var dataModuleType)) - { - throw new Exception($"Unknown data module {elementType}"); - } - Selectable.SetModified(); - var instance = (ModuleData)Activator.CreateInstance(dataModuleType); - var dataObject = new JObject - { - ["$type"] = $"{dataModuleType.FullName}, {dataModuleType.Assembly.GetName().Name}" - }; - var otherObject = JObject.Parse(IOProvider.ToJson(instance)); - foreach (var prop in otherObject) - { - dataObject[prop.Key] = prop.Value; - } - var trueType = new JObject - { - ["Name"] = dataModuleType.Name, - ["ModuleType"] = instance.ModuleType.AssemblyQualifiedName, - ["DataType"] = instance.DataType.AssemblyQualifiedName, - ["Data"] = null, - ["DataObject"] = dataObject - }; - (SerializedData["ModuleData"] as JArray)?.Add(trueType); - Classes.Add(dataModuleType.Name); - var selectable = GetSelectable(trueType); - Children.Add(selectable); - return selectable; - } - - /// - public override string Serialize() => SerializedData.ToString(); - /// - public override DataValue GetValue() => DataValue.FromJToken(SerializedData); -} \ No newline at end of file diff --git a/src/PatchManager.Parts/Selectables/PartSelectable.cs b/src/PatchManager.Parts/Selectables/PartSelectable.cs deleted file mode 100644 index 06ae5ed..0000000 --- a/src/PatchManager.Parts/Selectables/PartSelectable.cs +++ /dev/null @@ -1,155 +0,0 @@ -using System.Text.RegularExpressions; -using Newtonsoft.Json.Linq; -using PatchManager.Parts.Modifiables; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Selectables; - -namespace PatchManager.Parts.Selectables; - -/// -/// Represents a selectable for selection and transformation of part data -/// -public sealed class PartSelectable : BaseSelectable -{ - private bool _modified; - private bool _deleted; - - /// - /// Marks this part selectable as having been modified any level down - /// - public void SetModified() - { - _modified = true; - } - - /// - /// Marks this part as goneso - /// - public void SetDeleted() - { - SetModified(); - _deleted = true; - } - - private readonly string _originalData; - internal readonly JObject JObject; - private static readonly Regex Sanitizer = new("[^a-zA-Z0-9 -_]"); - private static string Sanitize(string str) => Sanitizer.Replace(str, ""); - private readonly Dictionary _moduleIndices; - private static JArray _serializedPartModules; - - internal PartSelectable(string data) - { - _originalData = data; - JObject = JObject.Parse(data); - _moduleIndices = new Dictionary(); - Classes = new List(); - Children = new List(); - var partData = JObject["data"]; - Name = (string)partData["partName"]; - foreach (var tag in ((string)partData["tags"]).Split(' ')) - { - Classes.Add(Sanitize(tag)); - } - - var serializedPartModules = partData["serializedPartModules"]; - _serializedPartModules = serializedPartModules as JArray; - var index = 0; - foreach (var module in serializedPartModules) - { - // var moduleData = module["ModuleData"]; - _moduleIndices[module["Name"].Value().Replace("PartComponent", "")] = index++; - Classes.Add(module["Name"].Value().Replace("PartComponent", "")); - Classes.Add(module["Name"].Value()); - // Classes.Add((string)moduleData["name"]); - Children.Add(new ModuleSelectable(module,this)); - } - Children.Add(new ResourceContainersSelectable((JArray)partData["resourceContainers"],this)); - // I'd add more but meh, too much work atm for me to then have to run simple tests, this is the MVP - // ReSharper disable once PossibleInvalidCastExceptionInForeachLoop - foreach (JProperty child in partData) - { - if (child.Name != "resourceContainers") - { - Children.Add(new JTokenSelectable(SetModified, child.Value, child.Name)); - } - } - } - - /// - public override List Children { get; } - - /// - public override string Name { get; } - - /// - public override List Classes { get; } - - private DataValue ConcatenateModuleData(int index) - { - DataValue value = new DataValue(DataValue.DataType.Dictionary, new Dictionary()); - foreach (var data in _serializedPartModules[index]["ModuleData"]) - { - var dataObject = DataValue.FromJToken(data["DataObject"]); - foreach (var kv in dataObject.Dictionary.Where(kv => kv.Key != "$type")) - { - value.Dictionary[kv.Key] = kv.Value; - } - } - return value; - } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - if (_moduleIndices.TryGetValue(@class.Replace("PartComponent", ""), out var index)) - { - classValue = ConcatenateModuleData(index); - return true; - } - classValue = null; - return false; - } - - /// - public override string ElementType => "parts_data"; - - /// - public override bool IsSameAs(ISelectable other) => other is PartSelectable ps && ps.Name == Name; - - /// - public override IModifiable OpenModification() - { - return new PartModifiable(this); - } - - /// - public override ISelectable AddElement(string elementType) - { - if (!PartsUtilities.ComponentModules.TryGetValue(elementType, out var mod)) - { - throw new Exception($"Unknown part module {elementType}"); - } - SetModified(); - var moduleObject = new JObject() - { - ["Name"] = mod.componentModule.Name, - ["ComponentType"] = mod.componentModule.AssemblyQualifiedName, - ["BehaviourType"] = mod.behaviour.AssemblyQualifiedName, - ["ModuleData"] = new JArray() - }; - (JObject["data"]["serializedPartModules"] as JArray)?.Add(moduleObject); - var selectable = new ModuleSelectable(moduleObject, this); - Classes.Add(elementType.Replace("PartComponent", "")); - Children.Add(selectable); - return selectable; - } - - - /// - public override string Serialize() => _modified ? _deleted ? "" : JObject.ToString() : _originalData; - - /// - public override DataValue GetValue() => OpenModification().Get(); -} \ No newline at end of file diff --git a/src/PatchManager.Parts/Selectables/ResourceContainerSelectable.cs b/src/PatchManager.Parts/Selectables/ResourceContainerSelectable.cs deleted file mode 100644 index d2caca5..0000000 --- a/src/PatchManager.Parts/Selectables/ResourceContainerSelectable.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching.Selectables; - -namespace PatchManager.Parts.Selectables; - -/// -/// A selectable that operates on resource container objects specifically -/// -public sealed class ResourceContainerSelectable : JTokenSelectable -{ - internal ResourceContainerSelectable(JObject container, PartSelectable selectable) - : base(selectable.SetModified, container, "resource_container") - { - Classes.Add((string)container["name"]); - } -} \ No newline at end of file diff --git a/src/PatchManager.Parts/Selectables/ResourceContainersSelectable.cs b/src/PatchManager.Parts/Selectables/ResourceContainersSelectable.cs deleted file mode 100644 index fc08870..0000000 --- a/src/PatchManager.Parts/Selectables/ResourceContainersSelectable.cs +++ /dev/null @@ -1,90 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; - -namespace PatchManager.Parts.Selectables; - -/// -/// Represents the resourceContainers field of a part json as a selectable -/// -public sealed class ResourceContainersSelectable : BaseSelectable -{ - private readonly JArray _containers; - private PartSelectable _selectable; - private Dictionary _resourceIndices; - - internal ResourceContainersSelectable(JArray containers, PartSelectable selectable) - { - _containers = containers; - _resourceIndices = new Dictionary(); - Children = new(); - ElementType = "resourceContainers"; - Classes = new(); - Name = "resourceContainers"; - _selectable = selectable; - var index = 0; - foreach (var container in containers) - { - _resourceIndices[(container as JObject)?["name"].Value() ?? string.Empty] = index++; - Classes.Add((container as JObject)?["name"].Value()); - Children.Add(new ResourceContainerSelectable(container as JObject, selectable)); - } - } - - /// - public override List Children { get; } - - /// - public override string Name { get; } - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - classValue = null; - if (_resourceIndices.TryGetValue(@class, out var index)) - { - classValue = DataValue.FromJToken(_containers[index]); - return true; - } - - return false; - } - - /// - public override string ElementType { get; } - - /// - public override bool IsSameAs(ISelectable other) => - other is ResourceContainersSelectable resourceContainersSelectable && - resourceContainersSelectable._containers == _containers; - - /// - public override IModifiable OpenModification() => null; - - /// - public override ISelectable AddElement(string elementType) - { - _selectable.SetModified(); - var obj = JObject.FromObject(new - { - name = elementType, - capacityUnits = 0.0, - initialUnits = 0.0, - NonStageable = false - }); - _containers.Add(obj); - var child = new ResourceContainerSelectable(obj, _selectable); - Children.Add(child); - // Console.WriteLine($"Added container: {obj}"); - return child; - } - - /// - public override string Serialize() => _containers.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(_containers); -} \ No newline at end of file diff --git a/src/PatchManager.Resources/PatchManager.Resources.csproj b/src/PatchManager.Resources/PatchManager.Resources.csproj deleted file mode 100644 index 3391f4b..0000000 --- a/src/PatchManager.Resources/PatchManager.Resources.csproj +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/PatchManager.Resources/ResourcesModule.cs b/src/PatchManager.Resources/ResourcesModule.cs deleted file mode 100644 index c778623..0000000 --- a/src/PatchManager.Resources/ResourcesModule.cs +++ /dev/null @@ -1,12 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.Shared.Modules; - -namespace PatchManager.Resources; - -/// -/// Resource patching module. -/// -[UsedImplicitly] -public class ResourcesModule : BaseModule -{ -} \ No newline at end of file diff --git a/src/PatchManager.Resources/Rulesets/ResourceRuleset.cs b/src/PatchManager.Resources/Rulesets/ResourceRuleset.cs deleted file mode 100644 index c3918a7..0000000 --- a/src/PatchManager.Resources/Rulesets/ResourceRuleset.cs +++ /dev/null @@ -1,53 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.Resources.Selectables; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.NewAssets; - -namespace PatchManager.Resources.Rulesets; - -/// -/// A patcher ruleset meant for adapting/creating resource definitions -/// -[PatcherRuleset("resources", "resources")] -public class ResourceRuleset : IPatcherRuleSet -{ - /// - public bool Matches(string label) => label == "resources"; - - /// - public ISelectable ConvertToSelectable(string type, string name, string jsonData) - { - var obj = JObject.Parse(jsonData); - if (obj.ContainsKey("isRecipe") && obj["isRecipe"]!.Value()) - { - return new RecipeSelectable(jsonData); - } - return new ResourceSelectable(jsonData); - } - - /// - public INewAsset CreateNew(List dataValues) - { - var isRecipe = false; - if (dataValues.Count == 2) - { - isRecipe = dataValues[1].Truthy; - } - - if (isRecipe) - { - var value = - $"{{\n \"version\": 0.1,\n \"useExternal\": false,\n \"isRecipe\": true,\n \"recipeData\": {{\n \"name\": \"{dataValues[0].String}\",\n \"displayNameKey\": \"Resource/DisplayName/Unknown\",\n \"abbreviationKey\": \"Resource/Abbreviation/UK\",\n \"resourceIconAssetAddress\": \"\",\n \"vfxFuelType\": \"NoFuel\",\n \"ingredients\": []\n }} \n}}"; - - return new NewGenericAsset("resources", dataValues[0].String, new RecipeSelectable(value)); - } - else - { - var value = - $"{{\n \"version\": 0.1,\n \"useExternal\": false,\n \"data\": {{\n \"name\": \"{dataValues[0].String}\",\n \"displayNameKey\": \"Resource/DisplayName/Unknown\",\n \"abbreviationKey\": \"Resource/Abbreviation/UK\",\n \"isTweakable\": true,\n \"isVisible\": true,\n \"massPerUnit\": 0,\n \"volumePerUnit\": 0,\n \"specificHeatCapacityPerUnit\": 0,\n \"flowMode\": 0,\n \"transferMode\": 0,\n \"costPerUnit\": 0,\n\t\"NonStageable\": false,\n \"resourceIconAssetAddress\": \"\",\n \"vfxFuelType\": \"NoFuel\" \n }} \n}}"; - return new NewGenericAsset("resources", dataValues[0].String, new ResourceSelectable(value)); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.Resources/Selectables/RecipeSelectable.cs b/src/PatchManager.Resources/Selectables/RecipeSelectable.cs deleted file mode 100644 index 2a3d3e9..0000000 --- a/src/PatchManager.Resources/Selectables/RecipeSelectable.cs +++ /dev/null @@ -1,116 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Modifiables; -using PatchManager.SassyPatching.Selectables; - -namespace PatchManager.Resources.Selectables; - -/// -/// Represents a selectable for the selection and transformation of recipe data -/// -public sealed class RecipeSelectable : BaseSelectable -{ - - private bool _modified; - private bool _deleted; - private readonly string _originalData; - internal readonly JObject JObject; - internal readonly JArray Ingredients; - internal readonly Dictionary IngredientIndices; - - /// - /// Marks this resource selectable as having been modified any level down - /// - public void SetModified() - { - _modified = true; - } - - /// - /// Marks this resource as goneso - /// - public void SetDeleted() - { - SetModified(); - _deleted = true; - } - - internal RecipeSelectable(string data) - { - _originalData = data; - JObject = JObject.Parse(data); - IngredientIndices = new Dictionary(); - Classes = new List { "recipe" }; - Children = new List(); - var resourceData = JObject["recipeData"]; - Name = (string)resourceData?["name"]; - Ingredients = (JArray)resourceData?["ingredients"]; - ElementType = "recipe"; - var index = 0; - foreach (var ingredient in Ingredients!) - { - IngredientIndices[ingredient["name"]!.Value()] = index++; - Classes.Add(ingredient["name"]!.Value()); - Children.Add( - new JTokenSelectable(SetModified, ingredient, tok => tok["name"].Value(), "ingredient")); - } - } - - /// - public override List Children { get; } - - /// - public override string Name { get; } - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - classValue = null; - if (@class == "recipe") - { - classValue = DataValue.FromJToken(JObject["recipeData"]); - return true; - } - if (IngredientIndices.TryGetValue(@class, out var index)) - { - classValue = DataValue.FromJToken(Ingredients[index]); - return true; - } - - return false; - - } - - /// - public override string ElementType { get; } - - /// - public override bool IsSameAs(ISelectable other) => other is RecipeSelectable rs && rs.Name == Name; - - /// - public override IModifiable OpenModification() => new JTokenModifiable(JObject["recipeData"], SetModified); - - /// - public override ISelectable AddElement(string elementType) - { - var obj = new JObject - { - ["name"] = elementType, - ["unitsPerRecipeUnit"] = 0.00 - }; - var child = new JTokenSelectable(SetModified, obj, tok => tok["name"].Value(), "ingredient"); - Children.Add(child); - Ingredients.Add(obj); - return child; - } - - /// - public override string Serialize() => _modified ? _deleted ? "" : JObject.ToString() : _originalData; - - /// - public override DataValue GetValue() => OpenModification().Get(); -} \ No newline at end of file diff --git a/src/PatchManager.Resources/Selectables/ResourceSelectable.cs b/src/PatchManager.Resources/Selectables/ResourceSelectable.cs deleted file mode 100644 index bc1aba9..0000000 --- a/src/PatchManager.Resources/Selectables/ResourceSelectable.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Modifiables; - -namespace PatchManager.Resources.Selectables; - -/// -/// Represents a selectable for the selection and transformation of resource data -/// -public class ResourceSelectable : BaseSelectable -{ - private bool _modified; - private bool _deleted; - - - /// - /// Marks this resource selectable as having been modified any level down - /// - public void SetModified() - { - _modified = true; - } - - /// - /// Marks this resource as goneso - /// - public void SetDeleted() - { - SetModified(); - _deleted = true; - } - - private readonly string _originalData; - internal readonly JObject JObject; - - internal ResourceSelectable(string data) - { - _originalData = data; - JObject = JObject.Parse(data); - Classes = new() { "resource" }; - Children = new(); - var resourceData = JObject["data"]; - Name = (string)resourceData["name"]; - ElementType = "resource"; - } - - /// - public override List Children { get; } - - /// - public override string Name { get; } - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - classValue = null; - if (@class == "resource") - { - classValue = DataValue.FromJToken(JObject["data"]); - return true; - } - return false; - } - - /// - public override string ElementType { get; } - - /// - public override bool IsSameAs(ISelectable other) => other is ResourceSelectable rs && rs.Name == Name; - - /// - public override IModifiable OpenModification() => new JTokenModifiable(JObject["data"], SetModified); - - /// - public override ISelectable AddElement(string elementType) => throw new InvalidOperationException(); - - /// - public override string Serialize() => _modified ? _deleted ? "" : JObject.ToString() : _originalData; - - /// - public override DataValue GetValue() => OpenModification().Get(); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Directory.Build.props b/src/PatchManager.SassyPatching.Tests/Directory.Build.props deleted file mode 100644 index 9686a6e..0000000 --- a/src/PatchManager.SassyPatching.Tests/Directory.Build.props +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - $(SolutionDir)/build/bin/testing/$(MSBuildProjectName) - $(SolutionDir)build/obj/testing/$(MSBuildProjectName) - - \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/ParsingTests.cs b/src/PatchManager.SassyPatching.Tests/ParsingTests.cs deleted file mode 100644 index 1a1e540..0000000 --- a/src/PatchManager.SassyPatching.Tests/ParsingTests.cs +++ /dev/null @@ -1,3084 +0,0 @@ -using PatchManager.SassyPatching.Tests.Validators; -using PatchManager.SassyPatching.Tests.Validators.Attributes; -using PatchManager.SassyPatching.Tests.Validators.Expressions; -using PatchManager.SassyPatching.Tests.Validators.Selectors; -using PatchManager.SassyPatching.Tests.Validators.Statements; -using PatchManager.SassyPatching.Tests.Validators.Statements.FunctionLevel; -using PatchManager.SassyPatching.Tests.Validators.Statements.SelectionLevel; -using PatchManager.SassyPatching.Tests.Validators.Statements.TopLevel; -// ReSharper disable RedundantEmptyObjectOrCollectionInitializer - -namespace PatchManager.SassyPatching.Tests; - -/// -/// A class containing all of the tests for the parser and the Transformer class -/// -public class ParsingTests -{ -#pragma warning disable CS8618 - private Transformer _tokenTransformer; -#pragma warning restore CS8618 - - /// - /// Sets up the parser tests by creating the transformer to be tested - /// - [SetUp] - public void Setup() - { - _tokenTransformer = new Transformer(Assert.Fail); - } - - private class FailErrorListener : IAntlrErrorListener - { - internal static readonly FailErrorListener Instance = new(); - private FailErrorListener() {} - public void SyntaxError(TextWriter output, IRecognizer recognizer, IToken offendingSymbol, int line, int charPositionInLine, - string msg, RecognitionException e) - { - Assert.Fail($"{line}:{charPositionInLine}: {msg}"); - } - } - - private SassyPatch Parse(string testPatch) - { - var charStream = CharStreams.fromString(testPatch); - var lexer = new sassy_lexer(charStream); - var tokenStream = new CommonTokenStream(lexer); - var parser = new sassy_parser(tokenStream); - parser.AddErrorListener(FailErrorListener.Instance); - var patchContext = parser.patch(); - _tokenTransformer.Errored = false; - var patch = _tokenTransformer.Visit(patchContext) as SassyPatch; - Assert.That(_tokenTransformer.Errored, Is.False); - return patch!; - } - - private void Match(string patch, ParseValidator validator) - { - var parsed = Parse(patch); - Assert.That(validator.Validate(parsed), Is.True, "Parse tree does not match the validation criterion"); - } - - #region Top Level Statement Tests - - /// - /// Tests single line comments - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests single line comments")] - public void SingleLineComments() - { - const string patch = - @" -// This is a single line comment -$variable: 5; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }; - - Match(patch, validator); - } - - /// - /// Tests single line comments - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests multi line comments")] - public void MultiLineComment() - { - const string patch = - @" -/* - * This is a multiline comment - */ -$variable: 5; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }; - Match(patch, validator); - } - - /// - /// Tests an import declaration - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an import declaration")] - public void ImportDeclaration() - { - const string patch = @" -@use 'a:b:c'; -"; - var validator = new PatchValidator - { - new ImportValidator - { - Library = "a:b:c" - } - }; - Match(patch, validator); - } - - - /// - /// Tests a top level variable declaration - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a top level variable declaration")] - public void TopLevelVariableDeclaration() - { - const string patch = - @" -$variable: 5; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a function definition w/o any arguments or body - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a function definition w/o any arguments or body")] - public void FunctionDefinitionNoArgumentsNoBody() - { - const string patch = - @" -@function test-function() { -} -"; - var validator = new PatchValidator - { - new FunctionValidator - { - Name = "test-function", - Arguments = new(), - Body = new() - } - }; - Match(patch, validator); - } - - /// - /// Tests a function definition w/ a single argument that has no default value and no body - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a function definition w/ a single argument that has no default value and no body")] - public void FunctionDefinitionSingleArgumentNoDefaultNoBody() - { - const string patch = - @" -@function test-function($arg) { -} -"; - var validator = new PatchValidator - { - new FunctionValidator - { - Name = "test-function", - Arguments = new() - { - new ArgumentValidator - { - Name = "arg" - } - }, - Body = new() - } - }; - Match(patch, validator); - } - - /// - /// Tests a function definition w/ a single argument that has a default value and no body - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a function definition w/ a single argument that has a default value and no body")] - public void FunctionDefinitionSingleArgumentDefaultNoBody() - { - const string patch = - @" -@function test-function($arg: 5) { -} -"; - var validator = new PatchValidator - { - new FunctionValidator - { - Name = "test-function", - Arguments = new() - { - new ArgumentValidator - { - Name = "arg", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }, - Body = new() - } - }; - Match(patch, validator); - } - - /// - /// Tests a function definition w/ a single argument that has a default value and a body that returns that value - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = - "Tests a function definition w/ a single argument that has a default value and a body that returns that value")] - public void FunctionDefinitionSingleArgumentDefaultReturn() - { - const string patch = - @" -@function test-function($arg: 5) { - @return $arg; -} -"; - var validator = new PatchValidator - { - new FunctionValidator - { - Name = "test-function", - Arguments = new() - { - new ArgumentValidator - { - Name = "arg", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }, - Body = new() - { - new ReturnValidator - { - ReturnedValue = new VariableReferenceValidator - { - VariableName = "arg" - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a mixin definition w/o any arguments or body - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a mixin definition w/o any arguments or body")] - public void MixinDefinitionNoArgumentsNoBody() - { - const string patch = - @" -@mixin test-mixin() { -} -"; - var validator = new PatchValidator - { - new MixinValidator - { - Name = "test-mixin", - Arguments = new(), - Body = new() - } - }; - Match(patch, validator); - } - - /// - /// Tests a mixin definition w/ a single argument that has no default value and no body - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a mixin definition w/ a single argument that has no default value and no body")] - public void MixinDefinitionSingleArgumentNoDefaultNoBody() - { - const string patch = - @" -@mixin test-mixin($arg) { -} -"; - var validator = new PatchValidator - { - new MixinValidator - { - Name = "test-mixin", - Arguments = new() - { - new ArgumentValidator - { - Name = "arg" - } - }, - Body = new() - } - }; - Match(patch, validator); - } - - /// - /// Tests a mixin definition w/ a single argument that has a default value and no body - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a mixin definition w/ a single argument that has a default value and no body")] - public void MixinDefinitionSingleArgumentDefaultNoBody() - { - const string patch = - @" -@mixin test-mixin($arg: 5) { -} -"; - var validator = new PatchValidator - { - new MixinValidator - { - Name = "test-mixin", - Arguments = new() - { - new ArgumentValidator - { - Name = "arg", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }, - Body = new() - } - }; - Match(patch, validator); - } - - /// - /// Tests a mixin definition w/ a single argument that has a default value and a body that returns that value - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = - "Tests a mixin definition w/ a single argument that has a default value and a body that returns that value")] - public void MixinDefinitionSingleArgumentDefaultBody() - { - const string patch = - @" -@mixin test-mixin($arg: 5) { - $var: $arg; -} -"; - var validator = new PatchValidator - { - new MixinValidator - { - Name = "test-mixin", - Arguments = new() - { - new ArgumentValidator - { - Name = "arg", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }, - Body = new() - { - new VariableDeclarationValidator() - { - Variable = "var", - Value = new VariableReferenceValidator - { - VariableName = "arg" - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a top level conditional statement w/ no else or else if - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a top level conditional statement w/ no else or else if")] - public void TopLevelConditionalNoElseIfNoElse() - { - const string patch = - @" -@if true { - $variable: 5; -} -"; - var validator = new PatchValidator - { - new ConditionalValidator - { - Condition = new ValueValidator - { - StoredDataValue = true - }, - Body = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a top level conditional statement w/ an else but no else if - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a top level conditional statement w/ an else but no else if")] - public void TopLevelConditionalNoElseIfElse() - { - const string patch = - @" -@if true -{ - $variable: 5; -} -@else -{ - $variable: 6; -} -"; - var validator = new PatchValidator - { - new ConditionalValidator - { - Condition = new ValueValidator - { - StoredDataValue = true - }, - Body = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }, - Else = new BlockValidator - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 6 - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a top level conditional statement w/ an else if but no else - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a top level conditional statement w/ an else if but no else")] - public void TopLevelConditionalElseIfNoElse() - { - const string patch = - @" -@if true -{ - $variable: 5; -} -@else-if false -{ - $variable: 6; -} -"; - var validator = new PatchValidator - { - new ConditionalValidator - { - Condition = new ValueValidator - { - StoredDataValue = true - }, - Body = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }, - Else = new ConditionalValidator - { - Condition = new ValueValidator - { - StoredDataValue = false - }, - Body = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 6 - } - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a top level conditional statement w/ an else if and an else - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a top level conditional statement w/ an else if and an else")] - public void TopLevelConditionalElseIfElse() - { - const string patch = - @" -@if true -{ - $variable: 5; -} -@else-if false -{ - $variable: 6; -} -@else -{ - $variable: 7; -} -"; - var validator = new PatchValidator - { - new ConditionalValidator - { - Condition = new ValueValidator - { - StoredDataValue = true - }, - Body = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }, - Else = new ConditionalValidator - { - Condition = new ValueValidator - { - StoredDataValue = false - }, - Body = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 6 - } - } - }, - Else = new BlockValidator - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 7 - } - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a simple selection block - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a simple selection block")] - public void SelectionBlock() - { - const string patch = - @" -* { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - } - }; - Match(patch, validator); - } - - #endregion - - #region Attribute Tests - - /// - /// Tests a selection block w/ an @stage attribute - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a selection block w/ an @stage attribute")] - public void StageAttribute() - { - const string patch = - @" -@stage 'init' -* { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new() - { - new RunAtStageAttributeValidator() - { - Stage = "init" - } - }, - Selector = new WildcardSelectorValidator(), - Actions = new() - } - }; - Match(patch, validator); - } - - #endregion - - #region Selector Tests - - /// - /// Tests an element selector - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an element selector")] - public void ElementSelector() - { - const string patch = - @" -element { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new ElementSelectorValidator - { - ElementName = "element" - }, - Actions = new(), - } - }; - Match(patch, validator); - } - - /// - /// Tests a class selector - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a class selector")] - public void ClassSelector() - { - const string patch = - @" -.class { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new ClassSelectorValidator - { - ClassName = "class" - }, - Actions = new(), - } - }; - Match(patch, validator); - } - - /// - /// Tests a name selector - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a name selector")] - public void NameSelector() - { - const string patch = - @" -#name { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new NameSelectorValidator - { - NamePattern = "name" - }, - Actions = new(), - } - }; - Match(patch, validator); - } - - /// - /// Tests a ruleset selector - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a ruleset selector")] - public void RulesetSelector() - { - const string patch = - @" -:ruleset { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new RulesetSelectorValidator - { - RulesetName = "ruleset" - }, - Actions = new(), - } - }; - Match(patch, validator); - } - - /// - /// Tests a combination selector - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a combination selector")] - public void CombinationSelector() - { - const string patch = - @" -a, b, c { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new CombinationSelectorValidator - { - new ElementSelectorValidator - { - ElementName = "a" - }, - new ElementSelectorValidator - { - ElementName = "b" - }, - new ElementSelectorValidator - { - ElementName = "c" - } - }, - Actions = new(), - } - }; - Match(patch, validator); - } - - /// - /// Tests a child selector - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a child selector")] - public void ChildSelector() - { - const string patch = - @" -a > .b { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new ChildSelectorValidator - { - Parent = new ElementSelectorValidator - { - ElementName = "a" - }, - Child = new ClassSelectorValidator - { - ClassName = "b" - } - }, - Actions = new(), - } - }; - Match(patch, validator); - } - - /// - /// Tests an intersection selector - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an intersection selector")] - public void IntersectionSelector() - { - const string patch = - @" -a b c { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new IntersectionSelectorValidator - { - new ElementSelectorValidator - { - ElementName = "a" - }, - new ElementSelectorValidator - { - ElementName = "b" - }, - new ElementSelectorValidator - { - ElementName = "c" - } - }, - Actions = new(), - } - }; - Match(patch, validator); - } - - /// - /// Tests a without class selector - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a without class selector")] - public void WithoutClassSelector() - { - const string patch = - @" -~.class { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WithoutClassSelectorValidator - { - ClassName = "class" - }, - Actions = new(), - } - }; - Match(patch, validator); - } - - /// - /// Tests a without name selector - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a without name selector")] - public void WithoutNameSelector() - { - const string patch = - @" -~#name { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WithoutNameSelectorValidator - { - NamePattern = "name" - }, - Actions = new(), - } - }; - Match(patch, validator); - } - - /// - /// Tests a wildcard selector - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a wildcard selector")] - public void WildcardSelector() - { - const string patch = - @" -* { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - } - }; - Match(patch, validator); - } - - /// - /// Tests a complex child selector - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a complex child selector")] - public void ComplexChildSelector() - { - const string patch = - @" -:parts * > ResourceContainers > * { - // Empty -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new ChildSelectorValidator - { - Parent = new ChildSelectorValidator - { - Parent = new IntersectionSelectorValidator - { - new RulesetSelectorValidator - { - RulesetName = "parts" - }, - new WildcardSelectorValidator() - }, - Child = new ElementSelectorValidator - { - ElementName = "ResourceContainers" - } - }, - Child = new WildcardSelectorValidator() - }, - Actions = new(), - } - }; - Match(patch, validator); - } - - #endregion - - #region Selection Action Tests - - /// - /// Tests a selection level variable declaration - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a selection level variable declaration")] - public void SelectionLevelVariableDeclaration() - { - const string patch = - @" -* { - $variable: 5; -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a selection level conditional statement w/ no else or else if - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a selection level conditional statement w/ no else or else if")] - public void SelectionLevelConditionalNoElseIfNoElse() - { - const string patch = - @" -* { - @if true { - $variable: 5; - } -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - { - new ConditionalValidator - { - Condition = new ValueValidator - { - StoredDataValue = true - }, - Body = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a selection level conditional statement w/ an else but no else if - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a selection level conditional statement w/ an else but no else if")] - public void SelectionLevelConditionalNoElseIfElse() - { - const string patch = - @" -* { - @if true - { - $variable: 5; - } - @else - { - $variable: 6; - } -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - { - new ConditionalValidator - { - Condition = new ValueValidator - { - StoredDataValue = true - }, - Body = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }, - Else = new BlockValidator - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 6 - } - } - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a selection level conditional statement w/ an else if but no else - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a selection level conditional statement w/ an else if but no else")] - public void SelectionLevelConditionalElseIfNoElse() - { - const string patch = - @" -* { - @if true - { - $variable: 5; - } - @else-if false - { - $variable: 6; - } -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - { - new ConditionalValidator - { - Condition = new ValueValidator - { - StoredDataValue = true - }, - Body = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }, - Else = new ConditionalValidator - { - Condition = new ValueValidator - { - StoredDataValue = false - }, - Body = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 6 - } - } - } - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a selection level conditional statement w/ an else if and an else - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a selection level conditional statement w/ an else if and an else")] - public void SelectionLevelConditionalElseIfElse() - { - const string patch = - @" -* { - @if true - { - $variable: 5; - } - @else-if false - { - $variable: 6; - } - @else - { - $variable: 7; - } -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - { - new ConditionalValidator - { - Condition = new ValueValidator - { - StoredDataValue = true - }, - Body = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 5 - } - } - }, - Else = new ConditionalValidator - { - Condition = new ValueValidator - { - StoredDataValue = false - }, - Body = new() - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 6 - } - } - }, - Else = new BlockValidator - { - new VariableDeclarationValidator - { - Variable = "variable", - Value = new ValueValidator - { - StoredDataValue = 7 - } - } - } - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a set value selection action - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a set value selection action")] - public void SetValueAction() - { - const string patch = - @" -// Note, don't ever run this unless you want to not have a game -* { - @set {}; -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - { - new SetValueValidator - { - Value = new ObjectValidator - { - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a deletion selection action - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a deletion selection action")] - public void DeletionAction() - { - const string patch = - @" -// Note, don't ever run this unless you want to not have a game -* { - @delete; -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - { - new DeleteValueValidator() - } - } - }; - Match(patch,validator); - } - - /// - /// Tests a merge selection action - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a merge selection action")] - public void MergeAction() - { - const string patch = - @" -* { - @merge {}; -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - { - new MergeValueValidator - { - Value = new ObjectValidator - { - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a field set selection action w/ an element key and no indexer - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a field set selection action w/ an element key and no indexer")] - public void FieldSetElementKeyNoIndexer() - { - const string patch = - @" -* { - x: 5; -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - { - new FieldValidator - { - FieldName = "x", - FieldValue = new ValueValidator - { - StoredDataValue = 5 - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a field set selection action w/ a string key and no indexer - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a field set selection action w/ a string key and no indexer")] - public void FieldSetStringKeyNoIndexer() - { - const string patch = - @" -* { - 'x': 5; -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - { - new FieldValidator - { - FieldName = "x", - FieldValue = new ValueValidator - { - StoredDataValue = 5 - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a field set selection action w/ an element key and a number indexer - /// -// [Test(TestOf = typeof(Transformer), Author = "Cheese", -// Description = "Tests a field set selection action w/ an element key and a number indexer")] -// public void FieldSetElementKeyNumberIndexer() -// { -// const string patch = -// @" -// * { -// x[0]: 5; -// } -// "; -// var validator = new PatchValidator -// { -// new SelectionBlockValidator -// { -// Attributes = new(), -// Selector = new WildcardSelectorValidator(), -// Actions = new() -// { -// new FieldValidator -// { -// FieldName = "x", -// Indexer = new NumberIndexerValidator -// { -// Index = 0 -// }, -// FieldValue = new ValueValidator -// { -// StoredDataValue = 5 -// } -// } -// } -// } -// }; -// Match(patch, validator); -// } - - /// - /// Tests a field set selection action w/ a string key and a number indexer - /// -// [Test(TestOf = typeof(Transformer), Author = "Cheese", -// Description = "Tests a field set selection action w/ a string key and a number indexer")] -// public void FieldSetStringKeyNumberIndexer() -// { -// const string patch = -// @" -// * { -// 'x'[0]: 5; -// } -// "; -// var validator = new PatchValidator -// { -// new SelectionBlockValidator -// { -// Attributes = new(), -// Selector = new WildcardSelectorValidator(), -// Actions = new() -// { -// new FieldValidator -// { -// FieldName = "x", -// Indexer = new NumberIndexerValidator -// { -// Index = 0 -// }, -// FieldValue = new ValueValidator -// { -// StoredDataValue = 5 -// } -// } -// } -// } -// }; -// Match(patch, validator); -// } - - /// - /// Tests a field set selection action w/ an element key and an element indexer - /// -// [Test(TestOf = typeof(Transformer), Author = "Cheese", -// Description = "Tests a field set selection action w/ an element key and an element indexer")] -// public void FieldSetElementKeyElementIndexer() -// { -// const string patch = -// @" -// * { -// x[y]: 5; -// } -// "; -// var validator = new PatchValidator -// { -// new SelectionBlockValidator -// { -// Attributes = new(), -// Selector = new WildcardSelectorValidator(), -// Actions = new() -// { -// new FieldValidator -// { -// FieldName = "x", -// Indexer = new ElementIndexerValidator -// { -// ElementName = "y" -// }, -// FieldValue = new ValueValidator -// { -// StoredDataValue = 5 -// } -// } -// } -// } -// }; -// Match(patch, validator); -// } - - /// - /// Tests a field set selection action w/ a string key and an element indexer - /// -// [Test(TestOf = typeof(Transformer), Author = "Cheese", -// Description = "Tests a field set selection action w/ a string key and an element indexer")] -// public void FieldSetStringKeyElementIndexer() -// { -// const string patch = -// @" -// * { -// 'x'[y]: 5; -// } -// "; -// var validator = new PatchValidator -// { -// new SelectionBlockValidator -// { -// Attributes = new(), -// Selector = new WildcardSelectorValidator(), -// Actions = new() -// { -// new FieldValidator -// { -// FieldName = "x", -// Indexer = new ElementIndexerValidator -// { -// ElementName = "y" -// }, -// FieldValue = new ValueValidator -// { -// StoredDataValue = 5 -// } -// } -// } -// } -// }; -// Match(patch, validator); -// } - - /// - /// Tests a field set selection action w/ an element key and a class indexer - /// -// [Test(TestOf = typeof(Transformer), Author = "Cheese", -// Description = "Tests a field set selection action w/ an element key and a class indexer")] -// public void FieldSetElementKeyClassIndexer() -// { -// const string patch = -// @" -// * { -// x[.y]: 5; -// } -// "; -// var validator = new PatchValidator -// { -// new SelectionBlockValidator -// { -// Attributes = new(), -// Selector = new WildcardSelectorValidator(), -// Actions = new() -// { -// new FieldValidator -// { -// FieldName = "x", -// Indexer = new ClassIndexerValidator -// { -// ClassName = "y" -// }, -// FieldValue = new ValueValidator -// { -// StoredDataValue = 5 -// } -// } -// } -// } -// }; -// Match(patch, validator); -// } - - /// - /// Tests a field set selection action w/ a string key and a class indexer - /// -// [Test(TestOf = typeof(Transformer), Author = "Cheese", -// Description = "Tests a field set selection action w/ a string key and a class indexer")] -// public void FieldSetStringKeyClassIndexer() -// { -// const string patch = -// @" -// * { -// 'x'[.y]: 5; -// } -// "; -// var validator = new PatchValidator -// { -// new SelectionBlockValidator -// { -// Attributes = new(), -// Selector = new WildcardSelectorValidator(), -// Actions = new() -// { -// new FieldValidator -// { -// FieldName = "x", -// Indexer = new ClassIndexerValidator -// { -// ClassName = "y" -// }, -// FieldValue = new ValueValidator -// { -// StoredDataValue = 5 -// } -// } -// } -// } -// }; -// Match(patch,validator); -// } - - /// - /// Tests a field set selection action w/ an element key and a string indexer - /// -// [Test(TestOf = typeof(Transformer), Author = "Cheese", -// Description = "Tests a field set selection action w/ an element key and a string indexer")] -// public void FieldSetElementKeyStringIndexer() -// { -// const string patch = -// @" -// * { -// x['y']: 5; -// } -// "; -// var validator = new PatchValidator -// { -// new SelectionBlockValidator -// { -// Attributes = new(), -// Selector = new WildcardSelectorValidator(), -// Actions = new() -// { -// new FieldValidator -// { -// FieldName = "x", -// Indexer = new StringIndexerValidator -// { -// Index = "y" -// }, -// FieldValue = new ValueValidator -// { -// StoredDataValue = 5 -// } -// } -// } -// } -// }; -// Match(patch, validator); -// } - - /// - /// Tests a field set selection action w/ a string key and a string indexer - /// -// [Test(TestOf = typeof(Transformer), Author = "Cheese", -// Description = "Tests a field set selection action w/ a string key and a string indexer")] -// public void FieldSetStringKeyStringIndexer() -// { -// const string patch = -// @" -// * { -// 'x'['y']: 5; -// } -// "; -// var validator = new PatchValidator -// { -// new SelectionBlockValidator -// { -// Attributes = new(), -// Selector = new WildcardSelectorValidator(), -// Actions = new() -// { -// new FieldValidator -// { -// FieldName = "x", -// Indexer = new StringIndexerValidator -// { -// Index = "y" -// }, -// FieldValue = new ValueValidator -// { -// StoredDataValue = 5 -// } -// } -// } -// } -// }; -// Match(patch, validator); -// } - - /// - /// Tests a nested selection block as a selection action - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a nested selection block as a selection action")] - public void NestedSelectionBlock() - { - const string patch = - @" -* { - * { - } -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a mixin include as a selection action - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a mixin include as a selection action")] - public void MixinInclude() - { - const string patch = - @" -* { - @include test-mixin() -} -"; - var validator = new PatchValidator - { - new SelectionBlockValidator - { - Attributes = new(), - Selector = new WildcardSelectorValidator(), - Actions = new() - { - new MixinIncludeValidator - { - MixinName = "test-mixin", - Arguments = new() - } - } - } - }; - Match(patch, validator); - } - - #endregion - - #region Expression Tests - - /// - /// Tests an implicit addition expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an implicit addition expression")] - public void ImplicitAddition() - { - const string patch = - @" -$x: +2; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new UnaryValidator - { - Child = new ValueValidator - { - StoredDataValue = 2 - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests an implicit subtraction expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an implicit subtraction expression")] - public void ImplicitSubtraction() - { - const string patch = - @" -$x: -2; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new UnaryValidator - { - Child = new ValueValidator - { - StoredDataValue = 2 - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests an implicit multiplication expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an implicit multiplication expression")] - public void ImplicitMultiplication() - { - const string patch = - @" -$x: *2; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new UnaryValidator - { - Child = new ValueValidator - { - StoredDataValue = 2 - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests an implicit division expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an implicit division expression")] - public void ImplicitDivision() - { - const string patch = - @" -$x: /2; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new UnaryValidator - { - Child = new ValueValidator - { - StoredDataValue = 2 - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a variable reference expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a variable reference expression")] - public void VariableReference() - { - const string patch = - @" -$x: $y; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new VariableReferenceValidator - { - VariableName = "y" - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a negation expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a negation expression")] - public void Negate() - { - const string patch = - @" -$x: (-2); -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new UnaryValidator - { - Child = new ValueValidator - { - StoredDataValue = 2 - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a positive expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a positive expression")] - public void Positive() - { - const string patch = - @" -$x: (+2); -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new UnaryValidator - { - Child = new ValueValidator - { - StoredDataValue = 2 - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests an inversion expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an inversion expression")] - public void Inversion() - { - const string patch = - @" -$x: !false; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new UnaryValidator - { - Child = new ValueValidator - { - StoredDataValue = false - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a function call w/ no unnamed or named arguments - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a function call w/ no unnamed or named arguments")] - public void CallNoUnnamedNoNamed() - { - const string patch = - @" -$x: test-function(); -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new SimpleCallValidator - { - FunctionName = "test-function", - Arguments = new() - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a function call w/ an unnamed argument but no named arguments - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a function call w/ an unnamed argument but no named arguments")] - public void CallUnnamedNoNamed() - { - const string patch = - @" -$x: test-function(5); -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new SimpleCallValidator - { - FunctionName = "test-function", - Arguments = new() - { - new CallArgumentValidator - { - ArgumentValue = new ValueValidator - { - StoredDataValue = 5 - } - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a function call w/ a named argument but no unnamed arguments - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a function call w/ a named argument but no unnamed arguments")] - public void CallNoUnnamedNamed() - { - const string patch = - @" -$x: test-function($a: 5); -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new SimpleCallValidator - { - FunctionName = "test-function", - Arguments = new() - { - new CallArgumentValidator - { - ArgumentName = "a", - ArgumentValue = new ValueValidator - { - StoredDataValue = 5 - } - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a function call w/ a named argument and an unnamed argument - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests a function call w/ a named argument and an unnamed argument")] - public void CallUnnamedNamed() - { - const string patch = - @" -$x: test-function(6, $a: 5); -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new SimpleCallValidator - { - FunctionName = "test-function", - Arguments = new() - { - new CallArgumentValidator - { - ArgumentValue = new ValueValidator - { - StoredDataValue = 6 - } - }, - new CallArgumentValidator - { - ArgumentName = "a", - ArgumentValue = new ValueValidator - { - StoredDataValue = 5 - } - } - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a member call w/o any arguments - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a member call w/o any arguments")] - public void MemberCall() - { - const string patch = - @" -$x: $y:method(); -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new MemberCallValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - FunctionName = "method", - Arguments = new() - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a subscript expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a subscript expression")] - public void Subscript() - { - const string patch = - @" -$x: $y[$z]; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a multiplication expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a multiplication expression")] - public void Multiply() - { - const string patch = - @" -$x: $y * $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a division expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a division expression")] - public void Divide() - { - const string patch = - @" -$x: $y / $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a remainder expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a remainder expression")] - public void Remainder() - { - const string patch = - @" -$x: $y % $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests an addition expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an addition expression")] - public void Add() - { - const string patch = - @" -$x: $y + $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a subtraction expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a subtraction expression")] - public void Subtract() - { - const string patch = - @" -$x: $y - $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a greater than expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a greater than expression")] - public void GreaterThan() - { - const string patch = - @" -$x: $y > $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a lesser than expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a lesser than expression")] - public void LesserThan() - { - const string patch = - @" -$x: $y < $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a greater than equal expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a greater than equal expression")] - public void GreaterThanEqual() - { - const string patch = - @" -$x: $y >= $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a lesser than equal expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a lesser than equal expression")] - public void LesserThanEqual() - { - const string patch = - @" -$x: $y <= $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests an equal to expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an equal to expression")] - public void EqualTo() - { - const string patch = - @" -$x: $y == $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a not equal to expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a not equal to expression")] - public void NotEqualTo() - { - const string patch = - @" -$x: $y != $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests an and expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an and expression")] - public void And() - { - const string patch = - @" -$x: $y and $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests an or expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an or expression")] - public void Or() - { - const string patch = - @" -$x: $y or $z; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a ternary expression - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a ternary expression")] - public void Ternary() - { - const string patch = - @" -$x: $y if $z else $w; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new TernaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - Condition = new VariableReferenceValidator - { - VariableName = "z" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "w" - } - } - } - }; - Match(patch, validator); - } - - #endregion - - #region Operator Precedence Tests - - /// - /// Tests that multiplication has a higher precedence than addition - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests that multiplication has a higher precedence than addition")] - public void MultiplicativePrecedence() - { - const string patch = - @" -$x: $y * $z + $w * $v; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - }, - RightHandSide = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "w" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "v" - } - }, - } - } - }; - Match(patch, validator); - } - - /// - /// Tests that subscription has a higher precedence than addition - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", - Description = "Tests that subscription has a higher precedence than addition")] - public void SubscriptionPrecedence() - { - const string patch = - @" -$x: $y * $z + $w[$v]; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new BinaryValidator - { - LeftHandSide = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "y" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "z" - } - }, - RightHandSide = new BinaryValidator - { - LeftHandSide = new VariableReferenceValidator - { - VariableName = "w" - }, - RightHandSide = new VariableReferenceValidator - { - VariableName = "v" - } - }, - } - } - }; - Match(patch, validator); - } - - #endregion - - #region Value Tests - - /// - /// Tests a deletion value - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a deletion value")] - public void DeleteValue() - { - const string patch = - @" -$x: @delete; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new ValueValidator - { - StoredDataValue = new DataValue(DataValue.DataType.Deletion) - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a true value - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a true value")] - public void True() - { - const string patch = - @" -$x: true; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new ValueValidator - { - StoredDataValue = true - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a false value - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a false value")] - public void False() - { - const string patch = - @" -$x: false; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new ValueValidator - { - StoredDataValue = false - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a number value - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a number value")] - public void Number() - { - const string patch = - @" -$x: 6.75; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new ValueValidator - { - StoredDataValue = 6.75 - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a string value - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a string value")] - public void String() - { - const string patch = - @" -$x: 'a\nb\n'; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new ValueValidator - { - StoredDataValue = "a\nb\n" - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a null value - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a null value")] - public void None() - { - const string patch = - @" -$x: null; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new ValueValidator - { - StoredDataValue = new DataValue(DataValue.DataType.None) - } - } - }; - Match(patch, validator); - } - - /// - /// Tests a list value - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests a list value")] - public void List() - { - const string patch = - @" -$x: [1,'2',true,4,null]; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new ListValidator - { - new ValueValidator - { - StoredDataValue = 1 - }, - new ValueValidator - { - StoredDataValue = "2" - }, - new ValueValidator - { - StoredDataValue = true - }, - new ValueValidator - { - StoredDataValue = 4 - }, - new ValueValidator - { - StoredDataValue = new DataValue(DataValue.DataType.None) - } - } - } - }; - Match(patch, validator); - } - - /// - /// Tests an object value - /// - [Test(TestOf = typeof(Transformer), Author = "Cheese", Description = "Tests an object value")] - public void Object() - { - const string patch = - @" -$x: { - a: 1, - 'b': 2, -}; -"; - var validator = new PatchValidator - { - new VariableDeclarationValidator - { - Variable = "x", - Value = new ObjectValidator - { - new KeyValueValidator - { - Key = "a", - Value = new ValueValidator - { - StoredDataValue = 1 - } - }, - new KeyValueValidator - { - Key = "b", - Value = new ValueValidator - { - StoredDataValue = 2 - } - } - } - } - }; - Match(patch, validator); - } - - #endregion -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/PatchManager.SassyPatching.Tests.csproj b/src/PatchManager.SassyPatching.Tests/PatchManager.SassyPatching.Tests.csproj deleted file mode 100644 index aa462c1..0000000 --- a/src/PatchManager.SassyPatching.Tests/PatchManager.SassyPatching.Tests.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - - false - true - PatchManager.SassyPatching.Tests - $(NoWarn);NU1701 - - - - - - - - - - - - - - - diff --git a/src/PatchManager.SassyPatching.Tests/Usings.cs b/src/PatchManager.SassyPatching.Tests/Usings.cs deleted file mode 100644 index ace19e8..0000000 --- a/src/PatchManager.SassyPatching.Tests/Usings.cs +++ /dev/null @@ -1,18 +0,0 @@ -// ReSharper disable RedundantUsingDirective.Global -global using NUnit.Framework; -global using PatchManager.SassyPatching; -global using PatchManager.SassyPatching.Nodes; -global using PatchManager.SassyPatching.Nodes.Expressions; -global using PatchManager.SassyPatching.Nodes.Expressions.Unary; -global using PatchManager.SassyPatching.Nodes.Expressions.Binary; -global using PatchManager.SassyPatching.Nodes.Selectors; -global using PatchManager.SassyPatching.Nodes.Attributes; -global using PatchManager.SassyPatching.Nodes.Statements; -global using PatchManager.SassyPatching.Nodes.Statements.TopLevel; -global using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; -global using PatchManager.SassyPatching.Nodes.Statements.FunctionLevel; -global using PatchManager.SassyPatching.Nodes.Indexers; -global using PatchManager.SassyPatching.Interfaces; -global using PatchManager.SassyPatching.Utility; -global using SassyPatchGrammar; -global using Antlr4.Runtime; \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/ArgumentValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/ArgumentValidator.cs deleted file mode 100644 index ceb7c0c..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/ArgumentValidator.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators; - -/// -/// Describes a validator for matching nodes of type -/// -public class ArgumentValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string Name = ""; - - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator Value = null; - - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(Argument node) - { - if (Name != node.Name) return false; - if (Value == null && node.Value != null) return false; - if (Value != null && node.Value == null) return false; - if (Value == null && node.Value == null) return true; - return Value!.Validate(node.Value!); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Attributes/RunAtStageAttributeValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Attributes/RunAtStageAttributeValidator.cs deleted file mode 100644 index dcc8f8a..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Attributes/RunAtStageAttributeValidator.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Attributes; -/// -/// Describes a validator for matching nodes of type -/// -public class RunAtStageAttributeValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string Stage = ""; - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(RunAtStageAttribute node) => node.Stage == Stage; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/BlockValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/BlockValidator.cs deleted file mode 100644 index 36c31a5..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/BlockValidator.cs +++ /dev/null @@ -1,44 +0,0 @@ -using System.Collections; - -namespace PatchManager.SassyPatching.Tests.Validators; - - -/// -/// Describes a validator for matching nodes of type -/// -public class BlockValidator : ParseValidator, IEnumerable -{ - private readonly List _validators = new(); - - /// - /// Gets an enumerator that enumerates over the validators contained in this validator - /// - /// The enumerator that enumerates over the validators contained in this validator - public IEnumerator GetEnumerator() - { - return _validators.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(Block node) - { - if (node.Children.Count != _validators.Count) return false; - return !_validators.Where((t, i) => !t.Validate(node.Children[i])).Any(); - } - /// - /// Adds a validator to the children of the tree that this validator describes - /// - /// The child validator that should be added to the end as a child of this validator - public void Add(ParseValidator parseValidator) - { - _validators.Add(parseValidator); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/CallArgumentValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/CallArgumentValidator.cs deleted file mode 100644 index e3c4e34..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/CallArgumentValidator.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators; - -/// -/// Describes a validator for matching nodes of type -/// -public class CallArgumentValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string ArgumentName = null; - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator ArgumentValue = new FalseValidator(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(CallArgument node) - { - if (ArgumentName != node.ArgumentName) return false; - return ArgumentValue.Validate(node.ArgumentValue); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/BinaryValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Expressions/BinaryValidator.cs deleted file mode 100644 index 366e80e..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/BinaryValidator.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Expressions; -/// -/// Describes a validator for matching nodes with a type derived from -/// -/// The unary node type that this validator will match -public class BinaryValidator : ParseValidator where T : Binary -{ - /// - /// A validator that is used to match against the corresponding node in a node with a type derived from - /// - public ParseValidator LeftHandSide = new FalseValidator(); - /// - /// A validator that is used to match against the corresponding node in a node with a type derived from - /// - public ParseValidator RightHandSide = new FalseValidator(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(T node) => - LeftHandSide.Validate(node.LeftHandSide) && RightHandSide.Validate(node.RightHandSide); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/ListValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Expressions/ListValidator.cs deleted file mode 100644 index b91f38e..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/ListValidator.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Collections; - -namespace PatchManager.SassyPatching.Tests.Validators.Expressions; -/// -/// Describes a validator for matching nodes of type -/// -public class ListValidator : ParseValidator, IEnumerable -{ - private readonly List _expressions = new(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(ListNode node) - { - if (node.Expressions.Count != _expressions.Count) return false; - return !_expressions.Where((x, y) => !x.Validate(node.Expressions[y])).Any(); - } - - /// - /// Gets an enumerator that enumerates over the validators contained in this validator - /// - /// The enumerator that enumerates over the validators contained in this validator - public IEnumerator GetEnumerator() - { - return _expressions.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Adds a validator to the children of the tree that this validator describes - /// - /// The child validator that should be added to the end as a child of this validator - public void Add(ParseValidator validator) - { - _expressions.Add(validator); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/MemberCallValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Expressions/MemberCallValidator.cs deleted file mode 100644 index 462c9f7..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/MemberCallValidator.cs +++ /dev/null @@ -1,31 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Expressions; -/// -/// Describes a validator for matching nodes of type -/// -public class MemberCallValidator : ParseValidator -{ /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator LeftHandSide = new FalseValidator(); - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string FunctionName = ""; - /// - /// A list of validators used to match against the corresponding list of nodes in a value of type - /// - public List Arguments = new(); - - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(MemberCall node) - { - if (!LeftHandSide.Validate(node.LeftHandSide)) return false; - if (node.FunctionName != FunctionName) return false; - if (Arguments.Count != node.Arguments.Count) return false; - return !Arguments.Where((x, y) => !x.Validate(node.Arguments[y])).Any(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/ObjectValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Expressions/ObjectValidator.cs deleted file mode 100644 index a62b686..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/ObjectValidator.cs +++ /dev/null @@ -1,43 +0,0 @@ -using System.Collections; - -namespace PatchManager.SassyPatching.Tests.Validators.Expressions; -/// -/// Describes a validator for matching nodes of type -/// -public class ObjectValidator : ParseValidator, IEnumerable -{ - private readonly List _initializers = new(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(ObjectNode node) - { - if (node.Initializers.Count != _initializers.Count) return false; - return !_initializers.Where((x, y) => !x.Validate(node.Initializers[y])).Any(); - } - - /// - /// Gets an enumerator that enumerates over the validators contained in this validator - /// - /// The enumerator that enumerates over the validators contained in this validator - public IEnumerator GetEnumerator() - { - return _initializers.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Adds a validator to the children of the tree that this validator describes - /// - /// The child validator that should be added to the end as a child of this validator - public void Add(KeyValueValidator initializer) - { - _initializers.Add(initializer); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/SimpleCallValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Expressions/SimpleCallValidator.cs deleted file mode 100644 index 185f7e2..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/SimpleCallValidator.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Expressions; -/// -/// Describes a validator for matching nodes of type -/// -public class SimpleCallValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string FunctionName = ""; - /// - /// A list of validators used to match against the corresponding list of nodes in a value of type - /// - public List Arguments = new(); - - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(SimpleCall node) - { - if (node.FunctionName != FunctionName) return false; - if (Arguments.Count != node.Arguments.Count) return false; - return !Arguments.Where((x, y) => !x.Validate(node.Arguments[y])).Any(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/TernaryValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Expressions/TernaryValidator.cs deleted file mode 100644 index 9d50131..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/TernaryValidator.cs +++ /dev/null @@ -1,28 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Expressions; -/// -/// Describes a validator for matching nodes of type -/// -public class TernaryValidator : ParseValidator -{ - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator LeftHandSide = new FalseValidator(); - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator Condition = new FalseValidator(); - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator RightHandSide = new FalseValidator(); - - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(Ternary node) => LeftHandSide.Validate(node.LeftHandSide) && - Condition.Validate(node.Condition) && - RightHandSide.Validate(node.RightHandSide); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/UnaryValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Expressions/UnaryValidator.cs deleted file mode 100644 index f983a4f..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/UnaryValidator.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Expressions; -/// -/// Describes a validator for matching nodes with a type derived from -/// -/// The unary node type that this validator will match -public class UnaryValidator : ParseValidator where T : Unary -{ - /// - /// A validator that is used to match against the corresponding node in a node with a type derived from - /// - public ParseValidator Child = new FalseValidator(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(T node) => Child.Validate(node.Child); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/ValueValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Expressions/ValueValidator.cs deleted file mode 100644 index 5dd5620..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/ValueValidator.cs +++ /dev/null @@ -1,93 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Expressions; -/// -/// Describes a validator for matching nodes of type -/// -public class ValueValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public DataValue StoredDataValue = new DataValue(DataValue.DataType.None); - - private static bool ListCompare(List leftHandSide, List rightHandSide) - { - if (leftHandSide.Count != rightHandSide.Count) - { - return false; - } - return !leftHandSide.Where((t, index) => !GetResult(t, rightHandSide[index])).Any(); - } - - private static bool DictionaryCompare(Dictionary leftHandSide, Dictionary rightHandSide) - { - if (leftHandSide.Count != rightHandSide.Count) - { - return false; - } - - foreach (var kv in leftHandSide) - { - if (rightHandSide.TryGetValue(kv.Key, out var rvalue)) - { - if (!GetResult(kv.Value, rvalue)) - { - return false; - } - } - else - { - return false; - } - } - return true; - } - - private static bool GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - if (leftHandSide.Type != rightHandSide.Type) return false; - - if (leftHandSide.IsBoolean) - { - return leftHandSide.Boolean == rightHandSide.Boolean; - } - - if (leftHandSide.IsReal) - { - // ReSharper disable once CompareOfFloatsByEqualityOperator - return leftHandSide.Real == rightHandSide.Real; - } - - if (leftHandSide.IsInteger) - { - return leftHandSide.Integer == rightHandSide.Integer; - } - - if (leftHandSide.IsString) - { - return leftHandSide.String == rightHandSide.String; - } - - if (leftHandSide.IsList) - { - return ListCompare(leftHandSide.List,rightHandSide.List); - } - - if (leftHandSide.IsDictionary) - { - return DictionaryCompare(leftHandSide.Dictionary, rightHandSide.Dictionary); - } - - return true; - } - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(ValueNode node) - { - // Now we compare equality between values - // Good thing is there should only be a few value types - return GetResult(StoredDataValue, node.StoredDataValue); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/VariableReferenceValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Expressions/VariableReferenceValidator.cs deleted file mode 100644 index 1d16a6d..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Expressions/VariableReferenceValidator.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Expressions; -/// -/// Describes a validator for matching nodes of type -/// -public class VariableReferenceValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string VariableName = ""; - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(VariableReference node) - { - return node.VariableName == VariableName; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/FalseValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/FalseValidator.cs deleted file mode 100644 index 8211953..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/FalseValidator.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators; - -/// -/// Describes a validator that never matches -/// -public class FalseValidator : ParseValidator -{ - /// - /// Given any node, it does not match - /// - /// Ignored - /// False - public override bool Validate(Node node) => false; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/KeyValueValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/KeyValueValidator.cs deleted file mode 100644 index b9d2f12..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/KeyValueValidator.cs +++ /dev/null @@ -1,22 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators; - -/// -/// Describes a validator for matching nodes of type -/// -public class KeyValueValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string Key = ""; - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator Value = new FalseValidator(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(KeyValueNode node) => node.Key == Key && Value.Validate(node.Value); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/ParseValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/ParseValidator.cs deleted file mode 100644 index 6b4b4de..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/ParseValidator.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators; - -/// -/// An abstract base class for validators that describe a tree structure for the results of a transformation to be matched against for validation -/// -public abstract class ParseValidator -{ - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public abstract bool Validate(Node node); -} - -/// -/// A generic extension to where it has a specific type of that the tree described by the validator will match against -/// -/// The type of to match against -public abstract class ParseValidator : ParseValidator where T : Node -{ - /// - /// An override of that validates whether the node is of the type that this matches against - /// - /// The node to match against - /// True if the node is of the type of node that this validator matches against and if the node matches against the tree defined by this validator - public sealed override bool Validate(Node node) => node is T tNode && Validate(tNode); - - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public abstract bool Validate(T node); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/PatchValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/PatchValidator.cs deleted file mode 100644 index 411d36d..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/PatchValidator.cs +++ /dev/null @@ -1,46 +0,0 @@ -using System.Collections; - -namespace PatchManager.SassyPatching.Tests.Validators; - -/// -/// Describes a validator for matching nodes of type -/// -public class PatchValidator : ParseValidator, IEnumerable -{ - private readonly List _validators = new(); - - - /// - /// Gets an enumerator that enumerates over the validators contained in this validator - /// - /// The enumerator that enumerates over the validators contained in this validator - public IEnumerator GetEnumerator() - { - return _validators.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(SassyPatch node) - { - if (node.Children.Count != _validators.Count) return false; - return !_validators.Where((t, i) => !t.Validate(node.Children[i])).Any(); - } - - /// - /// Adds a validator to the children of the tree that this validator describes - /// - /// The child validator that should be added to the end as a child of this validator - public void Add(ParseValidator parseValidator) - { - _validators.Add(parseValidator); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/ChildSelectorValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Selectors/ChildSelectorValidator.cs deleted file mode 100644 index 59fe785..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/ChildSelectorValidator.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Selectors; -/// -/// Describes a validator for matching nodes of type -/// -public class ChildSelectorValidator : ParseValidator -{ /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator Parent = new FalseValidator(); - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator Child = new FalseValidator(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(ChildSelector node) => Parent.Validate(node.Parent) && Child.Validate(node.Child); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/ClassSelectorValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Selectors/ClassSelectorValidator.cs deleted file mode 100644 index 581d978..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/ClassSelectorValidator.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Selectors; -/// -/// Describes a validator for matching nodes of type -/// -public class ClassSelectorValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string ClassName = ""; - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(ClassSelector node) => node.ClassName == ClassName; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/CombinationSelectorValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Selectors/CombinationSelectorValidator.cs deleted file mode 100644 index f2d72e7..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/CombinationSelectorValidator.cs +++ /dev/null @@ -1,41 +0,0 @@ -using System.Collections; - -namespace PatchManager.SassyPatching.Tests.Validators.Selectors; - -/// -/// Describes a validator for matching nodes of type -/// -public class CombinationSelectorValidator : ParseValidator, IEnumerable -{ - private readonly List _validators = new(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(CombinationSelector node) - { - if (_validators.Count != node.Selectors.Count) return false; - return !_validators.Where((x, y) => !x.Validate(node.Selectors[y])).Any(); - } - - /// - /// Gets an enumerator that enumerates over the validators contained in this validator - /// - /// The enumerator that enumerates over the validators contained in this validator - public IEnumerator GetEnumerator() - { - return _validators.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Adds a validator to the children of the tree that this validator describes - /// - /// The child validator that should be added to the end as a child of this validator - public void Add(ParseValidator validator) => _validators.Add(validator); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/ElementSelectorValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Selectors/ElementSelectorValidator.cs deleted file mode 100644 index 84ac5d4..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/ElementSelectorValidator.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Selectors; -/// -/// Describes a validator for matching nodes of type -/// -public class ElementSelectorValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string ElementName = ""; - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(ElementSelector node) => node.ElementName == ElementName; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/IntersectionSelectorValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Selectors/IntersectionSelectorValidator.cs deleted file mode 100644 index 74b76ac..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/IntersectionSelectorValidator.cs +++ /dev/null @@ -1,39 +0,0 @@ -using System.Collections; - -namespace PatchManager.SassyPatching.Tests.Validators.Selectors; -/// -/// Describes a validator for matching nodes of type -/// -public class IntersectionSelectorValidator : ParseValidator, IEnumerable -{ - private readonly List _validators = new(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(IntersectionSelector node) - { - if (_validators.Count != node.Selectors.Count) return false; - return !_validators.Where((x, y) => !x.Validate(node.Selectors[y])).Any(); - } - /// - /// Gets an enumerator that enumerates over the validators contained in this validator - /// - /// The enumerator that enumerates over the validators contained in this validator - public IEnumerator GetEnumerator() - { - return _validators.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() - { - return GetEnumerator(); - } - - /// - /// Adds a validator to the children of the tree that this validator describes - /// - /// The child validator that should be added to the end as a child of this validator - public void Add(ParseValidator validator) => _validators.Add(validator); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/NameSelectorValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Selectors/NameSelectorValidator.cs deleted file mode 100644 index 94a20df..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/NameSelectorValidator.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Selectors; -/// -/// Describes a validator for matching nodes of type -/// -public class NameSelectorValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string NamePattern = ""; - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(NameSelector node) => node.NamePattern == NamePattern; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/RulesetSelectorValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Selectors/RulesetSelectorValidator.cs deleted file mode 100644 index 7c1998c..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/RulesetSelectorValidator.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Selectors; -/// -/// Describes a validator for matching nodes of type -/// -public class RulesetSelectorValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string RulesetName = ""; - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(RulesetSelector node) => node.RulesetName == RulesetName; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/WildcardSelectorValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Selectors/WildcardSelectorValidator.cs deleted file mode 100644 index 4708500..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/WildcardSelectorValidator.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Selectors; -/// -/// Describes a validator for matching nodes of type -/// -public class WildcardSelectorValidator : ParseValidator -{ - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(WildcardSelector node) => true; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/WithoutClassSelectorValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Selectors/WithoutClassSelectorValidator.cs deleted file mode 100644 index b4311a3..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/WithoutClassSelectorValidator.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Selectors; -/// -/// Describes a validator for matching nodes of type -/// -public class WithoutClassSelectorValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string ClassName = ""; - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(WithoutClassSelector node) => node.ClassName == ClassName; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/WithoutNameSelectorValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Selectors/WithoutNameSelectorValidator.cs deleted file mode 100644 index f7a76f4..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Selectors/WithoutNameSelectorValidator.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Selectors; -/// -/// Describes a validator for matching nodes of type -/// -public class WithoutNameSelectorValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string NamePattern = ""; - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(WithoutNameSelector node) => node.NamePattern == NamePattern; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Statements/ConditionalValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Statements/ConditionalValidator.cs deleted file mode 100644 index d0d298a..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Statements/ConditionalValidator.cs +++ /dev/null @@ -1,34 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Statements; -/// -/// Describes a validator for matching nodes of type -/// -public class ConditionalValidator : ParseValidator -{ - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator Condition = new FalseValidator(); - /// - /// A list of validators used to match against the corresponding list of nodes in a value of type - /// - public List Body = new(); - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator Else = null; - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(Conditional node) - { - if (!Condition.Validate(node.Condition)) return false; - if (Body.Count != node.Body.Count) return false; - if (Body.Where((x, y) => !x.Validate(node.Body[y])).Any()) return false; - if (Else == null && node.Else == null) return true; - if (Else == null && node.Else != null) return false; - if (Else != null && node.Else == null) return false; - return Else!.Validate(node.Else!); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Statements/FunctionLevel/ReturnValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Statements/FunctionLevel/ReturnValidator.cs deleted file mode 100644 index c38a44c..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Statements/FunctionLevel/ReturnValidator.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Statements.FunctionLevel; -/// -/// Describes a validator for matching nodes of type -/// -public class ReturnValidator : ParseValidator -{ - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator ReturnedValue = new FalseValidator(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(Return node) - { - return ReturnedValue.Validate(node.ReturnedValue); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionBlockValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionBlockValidator.cs deleted file mode 100644 index 2f5e676..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionBlockValidator.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Statements; -/// -/// Describes a validator for matching nodes of type -/// -public class SelectionBlockValidator : ParseValidator -{ - /// - /// A list of validators used to match against the corresponding list of nodes in a value of type - /// - public List Attributes = new(); - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator Selector = new FalseValidator(); - /// - /// A list of validators used to match against the corresponding list of nodes in a value of type - /// - public List Actions = new(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(SelectionBlock node) - { - if (Attributes.Count != node.Attributes.Count) return false; - if (Attributes.Where((x, y) => !x.Validate(node.Attributes[y])).Any()) return false; - if (!Selector.Validate(node.Selector)) return false; - if (Actions.Count != node.Actions.Count) return false; - return !Actions.Where((x, y) => !x.Validate(node.Actions[y])).Any(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/DeleteValueValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/DeleteValueValidator.cs deleted file mode 100644 index 1348312..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/DeleteValueValidator.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Statements.SelectionLevel; -/// -/// Describes a validator for matching nodes of type -/// -public class DeleteValueValidator : ParseValidator -{ - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(DeleteValue node) => true; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/FieldValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/FieldValidator.cs deleted file mode 100644 index 71e493d..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/FieldValidator.cs +++ /dev/null @@ -1,32 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Statements.SelectionLevel; -/// -/// Describes a validator for matching nodes of type -/// -public class FieldValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string FieldName = ""; - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator Indexer = null; - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator FieldValue = new FalseValidator(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(Field node) - { - if (FieldName != node.FieldName) return false; - // if (Indexer == null && node.Indexer != null) return false; - // if (Indexer != null && node.Indexer == null) return false; - // if (Indexer != null && node.Indexer != null && !Indexer.Validate(node.Indexer)) return false; - return FieldValue.Validate(node.FieldValue); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/MergeValueValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/MergeValueValidator.cs deleted file mode 100644 index 84192d2..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/MergeValueValidator.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Statements.SelectionLevel; -/// -/// Describes a validator for matching nodes of type -/// -public class MergeValueValidator : ParseValidator -{ - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator Value = new FalseValidator(); - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(MergeValue node) => Value.Validate(node.Value); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/MixinIncludeValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/MixinIncludeValidator.cs deleted file mode 100644 index 4ff37f5..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/MixinIncludeValidator.cs +++ /dev/null @@ -1,30 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Statements.SelectionLevel; - -/// -/// Describes a validator for matching nodes of type -/// -public class MixinIncludeValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string MixinName = ""; - - /// - /// A list of validators used to match against the corresponding list of nodes in a value of type - /// - // ReSharper disable once CollectionNeverUpdated.Global - public List Arguments = new(); - - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(MixinInclude node) - { - if (node.MixinName != MixinName) return false; - if (Arguments.Count != node.Arguments.Count) return false; - return !Arguments.Where((x, y) => !x.Validate(node.Arguments[y])).Any(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/SetValueValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/SetValueValidator.cs deleted file mode 100644 index 87f86d6..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Statements/SelectionLevel/SetValueValidator.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Statements.SelectionLevel; - -/// -/// Describes a validator for matching nodes of type -/// -public class SetValueValidator : ParseValidator -{ - - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator Value = new FalseValidator(); - - - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(SetValue node) => Value.Validate(node.Value); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Statements/TopLevel/FunctionValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Statements/TopLevel/FunctionValidator.cs deleted file mode 100644 index 08933c2..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Statements/TopLevel/FunctionValidator.cs +++ /dev/null @@ -1,36 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Statements.TopLevel; -/// -/// Describes a validator for matching nodes of type -/// -public class FunctionValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string Name = ""; - - /// - /// A list of validators used to match against the corresponding list of nodes in a value of type - /// - public List Arguments = new(); - - /// - /// A list of validators used to match against the corresponding list of nodes in a value of type - /// - public List Body = new(); - - - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(Function node) - { - if (node.Name != Name) return false; - if (Arguments.Count != node.Arguments.Count) return false; - if (Arguments.Where((validator, idx) => !validator.Validate(node.Arguments[idx])).Any()) return false; - if (Body.Count != node.Body.Count) return false; - return !Body.Where((validator, idx) => !validator.Validate(node.Body[idx])).Any(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Statements/TopLevel/ImportValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Statements/TopLevel/ImportValidator.cs deleted file mode 100644 index 1708f88..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Statements/TopLevel/ImportValidator.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Statements.TopLevel; -/// -/// Describes a validator for matching nodes of type -/// -public class ImportValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string Library = ""; - - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(Import node) - { - return node.Library == Library; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Statements/TopLevel/MixinValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Statements/TopLevel/MixinValidator.cs deleted file mode 100644 index b02621c..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Statements/TopLevel/MixinValidator.cs +++ /dev/null @@ -1,35 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Statements.TopLevel; -/// -/// Describes a validator for matching nodes of type -/// -public class MixinValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string Name = ""; - - /// - /// A list of validators used to match against the corresponding list of nodes in a value of type - /// - public List Arguments = new(); - - /// - /// A list of validators used to match against the corresponding list of nodes in a value of type - /// - public List Body = new(); - - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(Mixin node) - { - if (node.Name != Name) return false; - if (Arguments.Count != node.Arguments.Count) return false; - if (Arguments.Where((validator, idx) => !validator.Validate(node.Arguments[idx])).Any()) return false; - if (Body.Count != node.Body.Count) return false; - return !Body.Where((validator, idx) => !validator.Validate(node.Body[idx])).Any(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching.Tests/Validators/Statements/VariableDeclarationValidator.cs b/src/PatchManager.SassyPatching.Tests/Validators/Statements/VariableDeclarationValidator.cs deleted file mode 100644 index 292da9f..0000000 --- a/src/PatchManager.SassyPatching.Tests/Validators/Statements/VariableDeclarationValidator.cs +++ /dev/null @@ -1,26 +0,0 @@ -namespace PatchManager.SassyPatching.Tests.Validators.Statements; -/// -/// Describes a validator for matching nodes of type -/// -public class VariableDeclarationValidator : ParseValidator -{ - /// - /// A field that is used to match against the corresponding field in a node of type - /// - public string Variable = ""; - /// - /// A validator that is used to match against the corresponding node in a node of type - /// - public ParseValidator Value = new FalseValidator(); - - /// - /// Determines if a node matches the tree defined by this validator - /// - /// The node to match against - /// True if the node matches against the tree defined by this validator - public override bool Validate(VariableDeclaration node) - { - if (node.Variable != Variable) return false; - return Value.Validate(node.Value); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Attributes/PatcherRulesetAttribute.cs b/src/PatchManager.SassyPatching/Attributes/PatcherRulesetAttribute.cs deleted file mode 100644 index 8a32f15..0000000 --- a/src/PatchManager.SassyPatching/Attributes/PatcherRulesetAttribute.cs +++ /dev/null @@ -1,38 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Interfaces; - -namespace PatchManager.SassyPatching.Attributes; - - - -/// -/// Used to define that a class will be used in the patcher to "get" a ruleset -/// For example [PatcherRuleset("parts")] creates the ":parts" ruleset -/// - -[AttributeUsage(AttributeTargets.Class)] -[BaseTypeRequired(typeof(IPatcherRuleSet))] -[MeansImplicitUse] -public class PatcherRulesetAttribute : Attribute -{ - /// - /// The name of the ruleset - /// - public readonly string RulesetName; - - /// - /// Labels that should always be loaded, as this ruleset will match them - /// - public string[] PreloadLabels; - - /// - /// Used to define that a class will be used in the patcher to "get" a ruleset - /// - /// The name of the ruleset - /// Labels that should always be loaded, as this ruleset will match them - public PatcherRulesetAttribute(string rulesetName, params string[] preloadLabels) - { - RulesetName = rulesetName; - PreloadLabels = preloadLabels; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Attributes/SassyConstantAttribute.cs b/src/PatchManager.SassyPatching/Attributes/SassyConstantAttribute.cs deleted file mode 100644 index d3ceeae..0000000 --- a/src/PatchManager.SassyPatching/Attributes/SassyConstantAttribute.cs +++ /dev/null @@ -1,11 +0,0 @@ -using JetBrains.Annotations; - -namespace PatchManager.SassyPatching.Attributes; - -[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] -[MeansImplicitUse] -public class SassyConstantAttribute : Attribute -{ - public string ConstantName; - public SassyConstantAttribute(string constantName) => ConstantName = constantName; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Attributes/SassyLibraryAttribute.cs b/src/PatchManager.SassyPatching/Attributes/SassyLibraryAttribute.cs deleted file mode 100644 index 47582a1..0000000 --- a/src/PatchManager.SassyPatching/Attributes/SassyLibraryAttribute.cs +++ /dev/null @@ -1,31 +0,0 @@ -using JetBrains.Annotations; - -namespace PatchManager.SassyPatching.Attributes; - -/// -/// Represents a builtin (C#) library for the sassy patcher execution engine -/// -[AttributeUsage(AttributeTargets.Class)] -[MeansImplicitUse] -public class SassyLibraryAttribute : Attribute -{ - /// - /// The mod id of the library, this is the part before the ":" in an @use, doesn't have to correspond to the mod guid of the mod defining this library - /// - public string Mod; - /// - /// The actual name of the library, this is the part after the colon - /// - public string Library; - - /// - /// Define this as a builtin library - /// - /// The mod id of the library - /// The actual name of the library, this is the part after the colon - public SassyLibraryAttribute(string mod, string library) - { - Mod = mod; - Library = library; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Attributes/SassyMethodAttribute.cs b/src/PatchManager.SassyPatching/Attributes/SassyMethodAttribute.cs deleted file mode 100644 index 65f4227..0000000 --- a/src/PatchManager.SassyPatching/Attributes/SassyMethodAttribute.cs +++ /dev/null @@ -1,26 +0,0 @@ -using JetBrains.Annotations; - -namespace PatchManager.SassyPatching.Attributes; - -/// -/// Defines this as a method for sassy patcher, it can define any argument type it wants, and reflection will be used to convert them at runtime -/// Method overloading is not allowed -/// -[AttributeUsage(AttributeTargets.Method)] -[MeansImplicitUse] -public class SassyMethodAttribute : Attribute -{ - /// - /// The name of the method inside of the runtime this will be called - /// - public string MethodName; - - /// - /// Initializes a new SassyMethodAttribute - /// - /// The name of the method in runtime - public SassyMethodAttribute(string methodName) - { - MethodName = methodName; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Attributes/SassyNameAttribute.cs b/src/PatchManager.SassyPatching/Attributes/SassyNameAttribute.cs deleted file mode 100644 index 0c0a952..0000000 --- a/src/PatchManager.SassyPatching/Attributes/SassyNameAttribute.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace PatchManager.SassyPatching.Attributes; - -[AttributeUsage(AttributeTargets.Parameter,AllowMultiple = false)] -public class SassyNameAttribute : Attribute -{ - public string ArgumentName; - public SassyNameAttribute(string argumentName) - { - ArgumentName = argumentName; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Attributes/VarArgsAttribute.cs b/src/PatchManager.SassyPatching/Attributes/VarArgsAttribute.cs deleted file mode 100644 index 8189a24..0000000 --- a/src/PatchManager.SassyPatching/Attributes/VarArgsAttribute.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace PatchManager.SassyPatching.Attributes; - -/// -/// Used on a parameter for a builtin method to change it from matching List<Value> to all the remaining arguments -/// -[AttributeUsage(AttributeTargets.Parameter)] -public class VarArgsAttribute : Attribute -{ - -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/BaseSelectable.cs b/src/PatchManager.SassyPatching/BaseSelectable.cs deleted file mode 100644 index 752436e..0000000 --- a/src/PatchManager.SassyPatching/BaseSelectable.cs +++ /dev/null @@ -1,70 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Interfaces; - -namespace PatchManager.SassyPatching; - -/// -/// A base class for selectables that implements most of the selection functions -/// -[PublicAPI] -public abstract class BaseSelectable : ISelectable -{ - /// - /// The children of this selectable - /// - public abstract List Children { get; } - - /// - public List SelectEverything() => Children; - - /// - /// The name of this selectable element - /// - public abstract string Name { get; } - - /// - public bool MatchesName(string name) => Name.MatchesPattern(name); - - /// - /// The classes that this selectable has, usually corresponds to the field names of the children (except for parts, in which its that + module type) - /// - public abstract List Classes { get; } - - /// - public bool MatchesClass(string @class) => Classes.Contains(@class); - - /// - /// Test if this selectable has a class, and if so, output the value of that class - /// - /// The class - /// The value of the class - /// True if it has the class, false otherwise - public abstract bool MatchesClass(string @class, out DataValue classValue); - - /// - /// The type of this selectable element (usually corresponds to the field name it is defined as, or the module type) - /// - public abstract string ElementType { get; } - - /// - public bool MatchesElement(string element) => ElementType == element; - - /// - public abstract bool IsSameAs(ISelectable other); - - /// - public abstract IModifiable OpenModification(); - - - - /// - public abstract ISelectable AddElement(string elementType); - - - /// - public abstract string Serialize(); - - /// - - public abstract DataValue GetValue(); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Builtins/ConfigBuiltins.cs b/src/PatchManager.SassyPatching/Builtins/ConfigBuiltins.cs deleted file mode 100644 index 3a727d6..0000000 --- a/src/PatchManager.SassyPatching/Builtins/ConfigBuiltins.cs +++ /dev/null @@ -1,18 +0,0 @@ -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Execution; - -namespace PatchManager.SassyPatching.Builtins; - -[SassyLibrary("builtin", "config")] -public class ConfigBuiltins -{ - [SassyMethod("get-config")] - public static DataValue GetConfig(Universe universe, string label, string name) => - universe.Configs.TryGetValue(label, out var labelDict) - ? labelDict.TryGetValue(name, out var result) ? result : new DataValue(DataValue.DataType.None) - : new DataValue(DataValue.DataType.None); - - [SassyMethod("get-configs")] - public static DataValue GetConfigs(Universe universe, string label) => - universe.Configs.TryGetValue(label, out var labelDict) ? labelDict : new Dictionary(); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Builtins/DebugBuiltins.cs b/src/PatchManager.SassyPatching/Builtins/DebugBuiltins.cs deleted file mode 100644 index 80352be..0000000 --- a/src/PatchManager.SassyPatching/Builtins/DebugBuiltins.cs +++ /dev/null @@ -1,34 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Execution; - -namespace PatchManager.SassyPatching.Builtins; - -/// -/// Contains a lot of builtin debug libraries for the sassy patch engine to use -/// -[SassyLibrary("builtin","debug"),PublicAPI] -public class DebugBuiltins -{ - /// - /// Logs a value into the console for debugging - /// - /// The universe in which this function is being called - /// The value to log - [SassyMethod("debug-log")] - public static void Log(Universe universe, DataValue value) - { - universe.MessageLogger(value.Type == DataValue.DataType.String ? value.String : value.ToString()); - } - - /// - /// Serializes a value - /// - /// The value to serialize - /// The serialized form of the value - [SassyMethod("serialize")] - public static string Serialize(DataValue value) - { - return value.ToString(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Builtins/DictionaryBuiltins.cs b/src/PatchManager.SassyPatching/Builtins/DictionaryBuiltins.cs deleted file mode 100644 index 6b0ad42..0000000 --- a/src/PatchManager.SassyPatching/Builtins/DictionaryBuiltins.cs +++ /dev/null @@ -1,54 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Attributes; - -namespace PatchManager.SassyPatching.Builtins; -/// -/// Object/dictionary builtins -/// -[SassyLibrary("builtin","dictionary")] -[PublicAPI] -public class DictionaryBuiltins -{ - [SassyMethod("dictionary.set")] - public static Dictionary Set(Dictionary dict, string key, DataValue value) - { - var result = new Dictionary(dict); - if (value.IsDeletion) - { - result.Remove(key); - } - else - { - result[key] = value; - } - return result; - } - - [SassyMethod("dictionary.merge")] - public static Dictionary Merge( - [SassyName("original-dict")] Dictionary original, - [SassyName("new-dict")] Dictionary toMerge - ) - { - var newDictionary = new Dictionary(original); - foreach (var (key, value) in toMerge) - { - newDictionary[key] = value; - } - return newDictionary; - } - - [SassyMethod("dictionary.keys")] - public static List Keys(Dictionary dict) => dict.Keys.ToList(); - - [SassyMethod("dictionary.values")] - public static List Values(Dictionary dict) => dict.Values.ToList(); - - - [SassyMethod("dictionary.remove")] - public static Dictionary Remove(Dictionary dict, string key) => - dict.Where(kv => kv.Key != key).ToDictionary(kv => kv.Key,kv=>kv.Value); - - [SassyMethod("dictionary.count")] - public static int Count(Dictionary dict) => dict.Count; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Builtins/FunctionalBuiltins.cs b/src/PatchManager.SassyPatching/Builtins/FunctionalBuiltins.cs deleted file mode 100644 index fbe029e..0000000 --- a/src/PatchManager.SassyPatching/Builtins/FunctionalBuiltins.cs +++ /dev/null @@ -1,78 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Execution; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Builtins; - -[SassyLibrary("builtin","functional"),PublicAPI] -public class FunctionalBuiltins -{ - - - /// - /// Gets a function from the global environment - /// - /// The global environment that is automatically filled in - /// The name of the function to get - /// A closure representing that function - [SassyMethod("get-function")] - public static PatchFunction GetFunction(GlobalEnvironment globalEnvironment, string name) - { - return globalEnvironment.AllFunctions[name]; - } - - /// - /// Invoke a closure w/ the given arguments - /// - /// The environment to run the closure in - /// - /// - /// - [SassyMethod("closure.invoke")] - public static DataValue Invoke(Environment env, PatchFunction closure, List arguments) - { - return closure.Execute(env, arguments); - } - - - /// - /// Binds arguments to the left side of a closure - /// - /// The closure to bind the arguments to - /// The arguments to be bound - /// A method that is the closure w/ the arguments having been bound - [SassyMethod("closure.bind")] - public static PatchFunction Bind(PatchFunction closure, List arguments) - { - if (closure is BoundPatchFunction boundPatchFunction) - { - var leftBindings = new List(boundPatchFunction.LeftBindings); - leftBindings.AddRange(arguments); - return new BoundPatchFunction(boundPatchFunction.InternalFunction, leftBindings, boundPatchFunction.RightBindings); - } - return new BoundPatchFunction(closure, arguments, new()); - } - - /// - /// Binds arguments to the right side of a closure - /// - /// The closure to bind the arguments to - /// The arguments to be bound - /// A method that is the closure w/ the arguments having been bound - [SassyMethod("closure.right-bind")] - public static PatchFunction RightBind(PatchFunction closure, List arguments) - { - if (closure is BoundPatchFunction boundPatchFunction) - { - // Make sure they get bound before the already right bound functions - // $x:right-bind(1):right-bind(2) should be equivalent to $x:right-bind(2,1) - var rightBindings = new List(arguments); - rightBindings.AddRange(boundPatchFunction.RightBindings); - return new BoundPatchFunction(boundPatchFunction.InternalFunction, boundPatchFunction.LeftBindings,rightBindings); - } - - return new BoundPatchFunction(closure, new(), arguments); - } - -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Builtins/ListBuiltins.cs b/src/PatchManager.SassyPatching/Builtins/ListBuiltins.cs deleted file mode 100644 index ae1faf8..0000000 --- a/src/PatchManager.SassyPatching/Builtins/ListBuiltins.cs +++ /dev/null @@ -1,232 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Execution; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Builtins; - -/// -/// This is the list library used by sassy patching, every method that is list specific in it is prepended w/ list. to prevent overloading -/// -[SassyLibrary("builtin", "list")] -[PublicAPI] -public class ListBuiltins -{ - /// - /// Copies a list and appends a value onto the copy and returns the copy - /// - /// The list to copy - /// The value to append - /// The new list w/ the value appended to it - [SassyMethod("list.append")] - public static List Append(List list, DataValue value) => new(list) { value }; - - /// - /// Copies a list and appends a list of values onto the copy and returns the copy - /// Same as the `+` operator between lists - /// - /// The list to copy - /// The list of values to append - /// The new list w/ the values appended to it - [SassyMethod("list.append-all")] - public static List AppendAll(List list, List values) - { - var result = new List(list); - result.AddRange(values); - return result; - } - - /// - /// Creates a new list out - /// - /// - /// - [SassyMethod("list.create")] - public static List Create([VarArgs] List varArgs) - { - return varArgs; - } - - private static int DefaultComparison(DataValue a, DataValue b) - { - if (a.IsInteger && b.IsInteger) - { - return a.Integer < b.Integer ? -1 : a.Integer == b.Integer ? 0 : 1; - } - - if (a.IsReal && b.IsInteger) - { - // ReSharper disable once CompareOfFloatsByEqualityOperator - return a.Real < b.Integer ? -1 : a.Real == b.Integer ? 0 : 1; - } - - if (a.IsInteger && b.IsReal) - { - // ReSharper disable once CompareOfFloatsByEqualityOperator - return a.Integer < b.Real ? -1 : a.Integer == b.Real ? 0 : 1; - } - - if (a.IsReal && b.IsReal) - { - // ReSharper disable once CompareOfFloatsByEqualityOperator - return a.Real < b.Real ? -1 : a.Real == b.Real ? 0 : 1; - } - - if (a.IsString && b.IsString) - { - return string.Compare(a.String, b.String, StringComparison.Ordinal); - } - - throw new Exception( - $"Cannot compare a value of type {a.Type.ToString().ToLowerInvariant()} and {b.Type.ToString().ToLowerInvariant()}"); - } - - private static int InvokeComparison(Environment env, PatchFunction comparator, DataValue a, DataValue b) - { - var result = comparator.Execute(env, new List - { - new PatchArgument - { - ArgumentDataValue = a - }, - new PatchArgument - { - ArgumentDataValue = b - }, - }); - if (result.IsInteger) - { - // A simple are these less - return (int)result.Integer; - } - - if (result.IsReal) - { - return (int)result.Real; - } - - throw new TypeConversionException(result.Type.ToString().ToLowerInvariant(), "integer"); - } - - /// - /// Sorts a list, using a comparison function if one is provided otherwise uses a default comparison algorithm - /// - /// - /// - /// The function to sort with, default null (due to closures not existing in the program yet), follows the C# comparison function - /// - [SassyMethod("list.sort")] - public static List Sort(Environment env, List list, PatchFunction comparator = null) - { - var copy = new List(list); - Comparison comparison = - comparator != null ? (x, y) => InvokeComparison(env, comparator, x, y) : DefaultComparison; - copy.Sort(comparison); - return copy; - } - - - /// - /// Copy a list, apply a function over the copy and return that copy - /// - /// The environment this is being ran in - /// - /// The function to apply to the list - /// The copy w/ the function applied over it - [SassyMethod("list.map")] - public static List Map( - Environment env, - List list, - PatchFunction closure - ) => - list.Select(value => closure.Execute(env, - new List - { - new() - { - ArgumentDataValue = value - } - })) - .ToList(); - - /// - /// Copy a list, apply a function over the copy to filter the lists - /// - /// The environment this is being ran in - /// - /// The function to apply to the list - /// The copy w/ the function applied over it - [SassyMethod("list.filter")] - public static List Filter( - Environment env, - List list, - PatchFunction closure - ) => - list.Where(value => closure.Execute(env, - new List - { - new() - { - ArgumentDataValue = value - } - }).Truthy) - .ToList(); - - /// - /// Aggregate a list into one value - /// - /// The environment of the list - /// - /// The starting value of the aggregation - /// The function to apply to take the aggregate - /// The aggregate value - [SassyMethod("list.reduce")] - public static DataValue Reduce( - Environment env, - List list, - [SassyName("initial-value")] DataValue initialValue, - PatchFunction closure - ) => - list.Aggregate(initialValue, - ( - current, - value - ) => closure.Execute(env, - new List - { - new() - { - ArgumentDataValue = current - }, - new() - { - ArgumentDataValue = value - } - })); - - /// - /// Gets the length of a list - /// - /// The list - /// The length of the list - [SassyMethod("list.length")] - public static int Length(List list) => list.Count; - - [SassyMethod("list.join")] - public static string ToString(List list, string separator = "") => - string.Join("", list.Select(x => x.IsString ? x.String : x.ToString())); - - [SassyMethod("list.remove")] - public static List Remove(List list, [SassyName("to-remove")] DataValue toRemove) => - list.Where(x => x != toRemove).ToList(); - - [SassyMethod("list.remove-all")] - public static List RemoveAll(List list, [SassyName("to-remove")] List toRemove) => - list.Where(x => toRemove.All(y => y != x)).ToList(); - - [SassyMethod("list.slice")] - public static List Slice(List list, int start, int end) => - list.Skip(start).Take(end-start).ToList(); - -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Builtins/MathBuiltins.cs b/src/PatchManager.SassyPatching/Builtins/MathBuiltins.cs deleted file mode 100644 index 197bc31..0000000 --- a/src/PatchManager.SassyPatching/Builtins/MathBuiltins.cs +++ /dev/null @@ -1,121 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Attributes; - -namespace PatchManager.SassyPatching.Builtins; - -/// -/// A builtin math library to make dealing with stuff easier -/// -[SassyLibrary("builtin", "math"), PublicAPI] -public class MathBuiltins -{ - #region Basic Math - - [SassyMethod("square-root")] - public static double SquareRoot(double value) => Math.Sqrt(value); - - [SassyMethod("cube-root")] - public static double CubeRoot(double value) => Math.Pow(value, 0.333333333333333333333333333333333333333333333333d); - - [SassyMethod("pow")] - public static double Pow(double x, double y) => Math.Pow(x, y); - - [SassyMethod("ln")] - public static double Ln(double a) => Math.Log(a); - - [SassyMethod("log")] - public static double Log(double a, double @base) => Math.Log(a, @base); - - [SassyMethod("log10")] - public static double Log10(double a) => Math.Log10(a); - - [SassyMethod("ceiling")] - public static double Ceiling(double a) => Math.Ceiling(a); - - [SassyMethod("floor")] - public static double Floor(double a) => Math.Floor(a); - - [SassyMethod("abs")] - public static double Abs(double a) => Math.Abs(a); - - [SassyMethod("max")] - public static double Max([VarArgs] List values) => values.Select(x => x.To()).Max(); - - [SassyMethod("min")] - public static double Min([VarArgs] List values) => values.Select(x => x.To()).Min(); - - [SassyMethod("list.max")] - public static double Max(List list) => list.Max(); - - [SassyMethod("list.min")] - public static double Min(List list) => list.Min(); - - [SassyMethod("round")] - public static double Round(double x) => Math.Round(x, MidpointRounding.AwayFromZero); - - [SassyMethod("sign")] - public static double Sign(double x) => Math.Sign(x); - - [SassyConstant("E")] public static double E => Math.E; - - #endregion - - #region Trigonometry - - [SassyMethod("sin")] - public static double Sin(double a) => Math.Sin(a); - - [SassyMethod("cos")] - public static double Cos(double a) => Math.Cos(a); - - [SassyMethod("tan")] - public static double Tan(double a) => Math.Tan(a); - - [SassyMethod("sinh")] - public static double Sinh(double a) => Math.Sinh(a); - - [SassyMethod("cosh")] - public static double Cosh(double a) => Math.Cosh(a); - - [SassyMethod("tanh")] - public static double Tanh(double a) => Math.Tanh(a); - - [SassyMethod("asin")] - public static double Asin(double a) => Math.Asin(a); - - [SassyMethod("acos")] - public static double Acos(double a) => Math.Acos(a); - - [SassyMethod("atan")] - public static double Atan(double a) => Math.Atan(a); - - [SassyMethod("atan2")] - public static double Atan2(double y, double x) => Math.Atan2(y, x); - - [SassyConstant("PI")] public static double Pi => Math.PI; - [SassyConstant("TAU")] public static double Tau => 2 * Pi; - - #endregion - - #region Other Math - - [SassyMethod("interpolate")] - public static double Lerp(double a, double b, double t) => (1 - t) * a + t * b; - - [SassyMethod("list.normalize")] - public static List Normalize(List vector) - { - var magnitude = Math.Sqrt(vector.Select(x => x * x).Sum()); - return vector.Select(x => x / magnitude).ToList(); - } - - [SassyMethod("normalize")] - public static List Normalize([VarArgs] List args) - { - var list = (from x in args select x.To()).ToList(); - return Normalize(list); - } - - - #endregion -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Builtins/MetaBuiltins.cs b/src/PatchManager.SassyPatching/Builtins/MetaBuiltins.cs deleted file mode 100644 index 1676456..0000000 --- a/src/PatchManager.SassyPatching/Builtins/MetaBuiltins.cs +++ /dev/null @@ -1,18 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Execution; - -namespace PatchManager.SassyPatching.Builtins; - -[SassyLibrary("builtin","meta")] -[PublicAPI] -public class MetaBuiltins -{ - [SassyMethod("exists-mod")] - public static bool ExistsMod(GlobalEnvironment globalEnvironment, [SassyName("mod-name")] string modName) => globalEnvironment.Universe.AllMods.Contains(modName); - - [SassyMethod("exists-function")] - public static bool ExistsFunction(GlobalEnvironment environment, [SassyName("function-name")] string functionName) => - environment.AllFunctions.Keys.Contains(functionName); - -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Builtins/ReflectionBuiltins.cs b/src/PatchManager.SassyPatching/Builtins/ReflectionBuiltins.cs deleted file mode 100644 index b21a34b..0000000 --- a/src/PatchManager.SassyPatching/Builtins/ReflectionBuiltins.cs +++ /dev/null @@ -1,23 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Attributes; - -namespace PatchManager.SassyPatching.Builtins; - -/// -/// This is the reflection library used by Sassy patching, its very simple as not much reflection is needed by the language -/// -[SassyLibrary("builtin","reflection")] -[PublicAPI] -public class ReflectionBuiltins -{ - /// - /// Gets the type of a value - /// - /// The value to get the type of - /// The values type as a lowercase string - [SassyMethod("typeof")] - public static string GetValueType(DataValue value) - { - return value.Type.ToString().ToLowerInvariant(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Builtins/StringBuiltins.cs b/src/PatchManager.SassyPatching/Builtins/StringBuiltins.cs deleted file mode 100644 index c4cca3d..0000000 --- a/src/PatchManager.SassyPatching/Builtins/StringBuiltins.cs +++ /dev/null @@ -1,42 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Builtins; - -/// -/// This contains all the builtin methods applying over strings -/// -[SassyLibrary("builtin","string"),PublicAPI] -public class StringBuiltins -{ - [SassyMethod("string.length")] - public static int Length([SassyName("string")] string str) => str.Length; - - [SassyMethod("string.reverse")] - public static string Reverse([SassyName("string")] string str) => string.Join("",str.Reverse()); - - [SassyMethod("string.starts-with")] - public static bool StartsWith([SassyName("string")] string str, [SassyName("other-string")] string otherString) => - str.StartsWith(otherString); - - - [SassyMethod("string.ends-with")] - public static bool EndsWith([SassyName("string")] string str, [SassyName("other-string")] string otherString) => - str.EndsWith(otherString); - - [SassyMethod("string.contains")] - public static bool Contains([SassyName("string")] string str, [SassyName("other-string")] string otherString) => - str.Contains(otherString); - - [SassyMethod("string.to-codepoint")] - public static char ToCodePoint([SassyName("string")] string str) - { - if (str.Length != 1) - throw new InvocationException("The length of the argument string must be one"); - return str[0]; - } - - [SassyMethod("codepoint-to-string")] - public static string CodePointToString([SassyName("codepoint")] char codePoint) => $"{codePoint}"; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Builtins/TypeConversion.cs b/src/PatchManager.SassyPatching/Builtins/TypeConversion.cs deleted file mode 100644 index 5532199..0000000 --- a/src/PatchManager.SassyPatching/Builtins/TypeConversion.cs +++ /dev/null @@ -1,87 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Attributes; - -namespace PatchManager.SassyPatching.Builtins; - - -/// -/// This contains all the builtin methods for converting between types -/// -[SassyLibrary("builtin","type-conversion"),PublicAPI] -public class TypeConversion -{ - /// - /// Used in a patch to convert a value to a boolean - /// - /// The value - /// A boolean form of the value - [SassyMethod("to-bool")] - public static bool ToBoolean(DataValue value) => value.Truthy; - - - /// - /// Used in a patch to convert a value to a real - /// - /// The value - /// The value interpreted as a real - [SassyMethod("to-real")] - public static double ToReal(DataValue value) - { - if (value.IsInteger) return value.Integer; - if (value.IsReal) return value.Real; - if (value.IsString) return double.Parse(value.String); - throw new InvalidCastException($"Cannot convert value of type {value.Type.ToString().ToLowerInvariant()} to real"); - } - - /// - /// Used in a patch to convert a value to a real - /// - /// The value - /// The value interpreted as a real - [SassyMethod("to-integer")] - public static long ToInteger(DataValue value) - { - if (value.IsInteger) return value.Integer; - if (value.IsReal) return (long)value.Real; - if (value.IsString) return long.Parse(value.String); - throw new InvalidCastException($"Cannot convert value of type {value.Type.ToString().ToLowerInvariant()} to integer"); - } - - /// - /// Used in a patch to convert a value to a string - /// - /// The value - /// A string form of the value - [SassyMethod("to-string")] - public static string ToString(DataValue value) - { - return value.IsString ? value.String : value.ToString(); - } - - [SassyMethod("dictionary.to-list")] - public static List> ToList(Dictionary dict) => dict.Select(kv => - new List() - { - DataValue.From(kv.Key), - kv.Value - }).ToList(); - - [SassyMethod("list.to-dictionary")] - public static Dictionary ToDictionary(List> list) - { - var newDict = new Dictionary(); - foreach (var value in list) - { - if (value.Count != 2) - throw new InvalidCastException("All values in $list must be 2-pairs of key, value"); - if (!value[0].IsString) - throw new InvalidCastException("Dictionary keys must be strings"); - newDict[value[0].String] = value[1]; - } - return newDict; - } - - [SassyMethod("string.to-list")] - public static List ToList([SassyName("string")] string str) => str.Select(x => $"{x}").ToList(); - - } \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Coordinate.cs b/src/PatchManager.SassyPatching/Coordinate.cs deleted file mode 100644 index f96b5ea..0000000 --- a/src/PatchManager.SassyPatching/Coordinate.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace PatchManager.SassyPatching; - -/// -/// Defines a location in a file -/// -/// The file the location is in -/// The line of the location -/// The column of the location -public record struct Coordinate(string Filename, int Line, int Column) -{ - /// - /// Get the string representation of the location - /// - /// A string representation in file:line:column format - public override string ToString() - { - return $"{Filename}:{Line}:{Column}"; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/DataValue.cs b/src/PatchManager.SassyPatching/DataValue.cs deleted file mode 100644 index 64bf402..0000000 --- a/src/PatchManager.SassyPatching/DataValue.cs +++ /dev/null @@ -1,1309 +0,0 @@ -using System.Collections; -using System.Globalization; -using System.Text; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Execution; - -namespace PatchManager.SassyPatching; - -/// -/// The basic value type that the sassy patching engine uses -/// It can be one of 8 different types of values, 6 of which correspond fully to JSON types w/ one extra type/value meant to "delete" whatever it is assigned to, and then closures -/// -public class DataValue -{ - /// - /// The types of values that a Value can be - /// - public enum DataType - { - /// - /// The type of null, corresponds to JSON null values - /// - None, - /// - /// The type of true/false, corresponds to JSON true/false values - /// - Boolean, - /// - /// The type of real numbers, stored as a double, corresponds to JSON floats - /// - Real, - /// - /// The type of integers, stored as a long, corresponds to JSON integers - /// - Integer, - /// - /// The type of strings, corresponds to JSON strings - /// - String, - /// - /// The type of lists, corresponds to JSON lists - /// - List, - /// - /// The type of dictionaries, corresponds to JSON objects - /// - Dictionary, - /// - /// The type of a value that when assigned to a variable/field deletes that variable/field - /// - Deletion, - - /// - /// The type of a closure, a function in a value - /// - Closure, - } - - /// - /// The type of this Value - /// - public readonly DataType Type; - - private readonly object _object; - - /// - /// Creates a new value w/ a specified type and stored value - /// - /// The type of this value - /// The value that is stored in this value, can be null for values of type and - public DataValue(DataType type, object o = null) - { - Type = type; - _object = o; - } - - private void CheckType(DataType toCheck) - { - if (Type != toCheck) - { - throw new IncorrectTypeException($"Attempting to read Value of type {Type} as a value of type {toCheck}"); - } - } - - /// - /// Is the type of this variable ? - /// - public bool IsNone => Type == DataType.None; - - /// - /// Is the type of this variable ? - /// - public bool IsBoolean => Type == DataType.Boolean; - - /// - /// Asserts this value is of type , - /// then returns the contained within - /// - /// Thrown if this value is not a value of type - public bool Boolean - { - get - { - CheckType(DataType.Boolean); - return (bool)_object; - } - } - - /// - /// Is the type of this variable ? - /// - public bool IsReal => Type == DataType.Real; - - /// - /// Asserts this value is of type , - /// then returns the contained within - /// - /// Thrown if this value is not a value of type - public double Real - { - get - { - CheckType(DataType.Real); - return (double)_object; - } - } - - /// - /// Is the type of this variable ? - /// - public bool IsInteger => Type == DataType.Integer; - - /// - /// Asserts this value is of type , - /// then returns the contained within - /// - /// Thrown if this value is not a value of type - public long Integer - { - get - { - CheckType(DataType.Integer); - return (long)_object; - } - } - - - /// - /// Is the type of this variable ? - /// - public bool IsString => Type == DataType.String; - - /// - /// Asserts this value is of type , - /// then returns the contained within - /// - /// Thrown if this value is not a value of type - public string String - { - get - { - CheckType(DataType.String); - return (string)_object; - } - } - - /// - /// Is the type of this variable ? - /// - public bool IsList => Type == DataType.List; - - /// - /// Asserts this value is of type , - /// then returns the contained within of which generic type argument is - /// - /// Thrown if this value is not a value of type - public List List - { - get - { - CheckType(DataType.List); - return (List)_object; - } - } - - /// - /// Is the type of this variable ? - /// - public bool IsDictionary => Type == DataType.Dictionary; - - /// - /// Asserts this value is of type , - /// then returns the contained within of which the key type is and the value type is - /// - /// Thrown if this value is not a value of type - public Dictionary Dictionary - { - get - { - CheckType(DataType.Dictionary); - return (Dictionary)_object; - } - } - - /// - /// Is the type of this variable ? - /// - public bool IsDeletion => Type == DataType.Deletion; - - /// - /// Is the type of this variable ? - /// - public bool IsClosure => Type == DataType.Closure; - - /// - /// Asserts this value is of type , - /// then returns the contained within - /// - /// Thrown if this value is not a value of type - public PatchFunction Closure - { - get - { - CheckType(DataType.Closure); - return (PatchFunction)_object; - } - } - - - /// - /// Does this value get interpreted as true in places where a is expected? - /// That is, is the value a and the value stored within true, or is the value anything but and ? - /// - public bool Truthy { - get - { - if (IsBoolean) return Boolean; - return !(IsNone || IsDeletion); - } - } - - /// - /// Creates a from a - /// - /// The value to be stored within the value - /// A with a type of and a stored value of - public static implicit operator DataValue(bool b) - { - return new DataValue(DataType.Boolean, b); - } - - /// - /// Creates a from a - /// - /// The value to be stored within the value - /// A with a type of and a stored value of - public static implicit operator DataValue(double d) - { - return new DataValue(DataType.Real, d); - } - - /// - /// Creates a from a - /// - /// The value to be stored within the value - /// A with a type of and a stored value of - public static implicit operator DataValue(long l) - { - return new DataValue(DataType.Integer, l); - } - - - /// - /// Creates a from a - /// - /// The value to be stored within the value - /// A with a type of and a stored value of - public static implicit operator DataValue(string s) - { - return new DataValue(DataType.String, s); - } - - /// - /// Creates a from a with the generic type argument being - /// - /// The value to be stored within the value - /// A with a type of and a stored value of - public static implicit operator DataValue(List l) - { - return new DataValue(DataType.List, l); - } - - /// - /// Creates a from a with the key type being and value type being - /// - /// The value to be stored within the value - /// A with a type of and a stored value of - public static implicit operator DataValue(Dictionary d) - { - return new DataValue(DataType.Dictionary, d); - } - - /// - /// Creates a from a - /// - /// The value to be stored within the value - /// A with a type of and a stored value of - public static implicit operator DataValue(PatchFunction c) - { - return new DataValue(DataType.Closure, c); - } - - /// - /// Converts a value to a string representation that can be interpreted by the engine as the exact value - /// - /// The string representation of the value - public override string ToString() - { - if (IsNone) - { - return "null"; - } - - if (IsBoolean) - { - return Boolean.ToString(); - } - - if (IsReal) - { - return Real.ToString(CultureInfo.InvariantCulture); - } - - if (IsString) - { - // return "'" + Regex.Escape(String) + "'"; - return String.Escape(); - } - - if (IsList) - { - return "[" + string.Join(",",List.Select(x => x.ToString())) + "]"; - } - - if (IsDictionary) - { - return "{" + string.Join(",",Dictionary.Select(x => x.Key.Escape() + $":{x.Value}")) + "}"; - } - - if (IsDeletion) - { - return "@delete"; - } - - if (IsClosure) - { - return ""; - } - - return ""; - } - - public T To() => (T)To(typeof(T)); - - public object To(Type t) - { - if (t == typeof(DataValue)) - { - return this; - } - - if (t == typeof(string)) - { - return String; - } - - if (t == typeof(Dictionary)) - { - return Dictionary; - } - - if (t == typeof(List)) - { - return List; - } - - if (t == typeof(DataValue[])) - { - return List.ToArray(); - } - - if (t == typeof(byte)) - { - return (byte)Integer; - } - - if (t == typeof(sbyte)) - { - return (sbyte)Integer; - } - - if (t == typeof(short)) - { - return (short)Integer; - } - - if (t == typeof(ushort)) - { - return (ushort)Integer; - } - - if (t == typeof(int)) - { - return (int)Integer; - } - - if (t == typeof(uint)) - { - return (uint)Integer; - } - - if (t == typeof(long)) - { - // ReSharper disable once RedundantCast - return (long)Integer; - } - - if (t == typeof(ulong)) - { - return (ulong)Integer; - } - - if (t == typeof(float)) - { - return (float)Real; - } - - if (t == typeof(double)) - { - return Real; - } - - if (t == typeof(bool)) - { - return Boolean; - } - - if (t == typeof(PatchFunction)) - { - return Closure; - } - - if (Type == DataType.None) - { - return null; - } - - if (ConvertValueToSingleRankArray(t, out var singleRankArray)) return singleRankArray; - - if (ConvertValueToMultiRankArray(t, out var multiRankArray)) return multiRankArray; - - if (ConvertValueToList(t, out var list)) return list; - - if (ConvertValueToDictionary(t, out var convertParameterValue)) return convertParameterValue; - - var obj = Activator.CreateInstance(t); - var dictionary = Dictionary; - foreach (var field in t.GetFields()) - { - field.SetValue(obj, dictionary[field.Name].To(field.FieldType)); - } - - return obj; - } - - private bool ConvertValueToDictionary(Type type, out object dictionary) - { - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Dictionary<,>)) - { - var keyType = type.GetGenericArguments()[0]; - var valueType = type.GetGenericArguments()[1]; - if (keyType != typeof(string)) - { - throw new TypeConversionException("Value", type.Name); - } - - var id = (IDictionary)Activator.CreateInstance(type); - var dict = Dictionary; - foreach (var kv in dict) - { - id[kv.Key] = kv.Value.To(valueType); - } - - { - dictionary = id; - return true; - } - } - - dictionary = null; - return false; - } - - private bool ConvertValueToList(Type type, out object list) - { - if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) - { - var valueType = type.GetGenericArguments()[0]; - var il = (IList)Activator.CreateInstance(type); - var tab = List; - foreach (var x in tab) - { - il.Add(x.To(valueType)); - } - - { - list = il; - return true; - } - } - - list = null; - return false; - } - - private bool ConvertValueToMultiRankArray(Type type, out object multiRankArray) - { - if (type.IsArray) - { - var tab = List; - var rank = type.GetArrayRank(); - var dimensions = new int[rank]; - var dimCounter = tab; - for (var i = 0; i < rank; i++) - { - dimensions[i] = dimCounter.Count; - if (i != rank - 1) - { - dimCounter = dimCounter[0].List; - } - } - - var arr = Array.CreateInstance(type.GetElementType()!, dimensions); - - void BuildArray(Array array, params int[] idx) - { - var idxCopy = new int[idx.Length + 1]; - idx.CopyTo(idxCopy, 0); - if (idx.Length == rank - 1) - { - for (var i = 0; i < array.GetLength(idx.Length); i++) - { - idxCopy[idx.Length] = i; - array.SetValue(tab[i].To(type.GetElementType()), idxCopy); - } - } - else - { - for (var i = 0; i < array.GetLength(idx.Length); i++) - { - idxCopy[idx.Length] = i; - BuildArray(array, idxCopy); - } - } - } - - BuildArray(arr); - { - multiRankArray = arr; - return true; - } - } - - multiRankArray = null; - return false; - } - - private bool ConvertValueToSingleRankArray(Type type, out object singleRankArray) - { - if (type.IsArray && type.GetArrayRank() == 1) - { - var tab = List; - var arr = Array.CreateInstance(type.GetElementType()!, tab.Count); - for (var i = 0; i < tab.Count; i++) - { - arr.SetValue(tab[i].To(type.GetElementType()), i); - } - - { - singleRankArray = arr; - return true; - } - } - - singleRankArray = null; - return false; - } - - /// - /// Creates a Value from a - /// - /// The token to convert to a value - /// A value that represents the data stored in the token - public static DataValue FromJToken(JToken token) - { - if (token == null) return new DataValue(DataType.None); - while (true) - { - switch (token.Type) - { - case JTokenType.Property: - token = ((JProperty)token).Value; - continue; - case JTokenType.Null or JTokenType.None: - return new DataValue(DataType.None); - case JTokenType.Float: - return (double)token; - case JTokenType.Integer: - return (long)token; - case JTokenType.Boolean: - return (bool)token; - case JTokenType.Date or JTokenType.String: - return (string)token; - case JTokenType.Array: - return token.Select(FromJToken).ToList(); - case JTokenType.Object: - { - Dictionary values = new(); - foreach (var jToken in token) - { - var jProperty = (JProperty)jToken; - values[jProperty.Name] = FromJToken(jProperty.Value); - } - - return values; - } - default: - return new DataValue(DataType.None); - } - } - } - - /// - /// Converts a value to a json.net object - /// - /// A JToken that represents the data in this object - public JToken ToJToken() - { - if (IsBoolean) - { - return new JValue(Boolean); - } - - if (IsReal) - { - return new JValue(Real); - } - - if (IsInteger) - { - return new JValue(Integer); - } - - if (IsString) - { - return new JValue(String); - } - - if (IsList) - { - var array = new JArray(); - foreach (var value in List) - { - array.Add(value.ToJToken()); - } - return array; - } - - if (IsDictionary) - { - var obj = new JObject(); - foreach (var kvPair in Dictionary) - { - obj[kvPair.Key] = kvPair.Value.ToJToken(); - } - return obj; - } - - return null; - } - private static bool ConvertGenericListOrDictionaryToValue(object value, Type type, out DataValue listOrDictionaryDataValue) - { - switch (type.IsGenericType) - { - case true when type.GetGenericTypeDefinition() == typeof(Dictionary<,>): - { - var keyType = type.GetGenericArguments()[0]; - if (keyType != typeof(string)) - { - throw new TypeConversionException(type.FullName, "Value"); - } - - var dict = (IDictionary)value; - Dictionary newData = new(); - foreach (var k in dict.Keys) - { - var ks = (string)k; - newData[ks] = From(dict[k]); - } - - { - listOrDictionaryDataValue = newData; - return true; - } - } - case true when type.GetGenericTypeDefinition() == typeof(List<>): - { - listOrDictionaryDataValue = ((from object v in (IList)value select From(v)).ToList()); - return true; - } - } - - listOrDictionaryDataValue = null; - return false; - } - - private static bool ConvertMultiRankArrayToValue(object value, Type t, out DataValue multiRankArrayDataValue) - { - if (t.IsArray) - { - var a = (Array)value; - var outermostDimension = new List(); - - void TraverseRank(List containingDimension, Array arr, int r, params int[] idx) - { - var size = a.GetLength(r); - var idxCopy = new int[idx.Length + 1]; - idx.CopyTo(idxCopy, 0); - if (r == a.Rank - 1) - { - for (var i = 0; i < size; i++) - { - idxCopy[idx.Length] = i; - var v = arr.GetValue(idxCopy); - containingDimension.Add(From(v)); - } - } - else - { - for (var i = 0; i < size; i++) - { - idxCopy[idx.Length] = i; - var currentDimension = new List(); - TraverseRank(currentDimension, arr, r + 1, idxCopy); - outermostDimension.Add(currentDimension); - } - } - } - - - TraverseRank(outermostDimension, a, 0); - { - multiRankArrayDataValue = outermostDimension; - return true; - } - } - - multiRankArrayDataValue = null; - return false; - } - - private static bool ConvertSingleRankArrayToValue(object value, Type type, out DataValue singleRankArray) - { - if (type.IsArray && type.GetArrayRank() == 1) - { - var arr = (Array)value; - List vs = new List(); - foreach (var obj in arr) - { - vs.Add(From(obj)); - } - - { - singleRankArray = vs; - return true; - } - } - - singleRankArray = null; - return false; - } - public static DataValue From(object value) - { - switch (value) - { - case null: - return new DataValue(DataType.None); - case DataValue v: - return v; - case bool b: - return b; - case byte bv: - return bv; - case sbyte sbv: - return sbv; - case short sv: - return sv; - case ushort usv: - return usv; - case int iv: - return iv; - case uint uiv: - return uiv; - case long slv: - return slv; - case ulong ulv: - return ulv; - case float f: - return f; - case double d: - return d; - case string s: - return s; - case List lv: - return lv; - case DataValue[] av: - return av.ToList(); - case Dictionary dv: - return dv; - case PatchFunction pf: - return pf; - case Delegate d: - return new ManagedPatchFunction(d.Method, d.Target); - } - - var t = value.GetType(); - - if (ConvertSingleRankArrayToValue(value, t, out var singleRankArray)) return singleRankArray; - if (ConvertMultiRankArrayToValue(value, t, out var multiRankArrayValue)) return multiRankArrayValue; - if (ConvertGenericListOrDictionaryToValue(value, t, out var listOrDictionaryValue)) return listOrDictionaryValue; - Dictionary objectData = new(); - - - // Only store public data - foreach (var field in t.GetFields()) - { - objectData[field.Name] = From(field.GetValue(value)); - } - - return objectData; - } - - - public static readonly DataValue Null = new(DataType.None); - - public static bool operator ==(DataValue leftHandSide, DataValue rightHandSide) - { - if (ReferenceEquals(leftHandSide, null) || ReferenceEquals(rightHandSide, null)) - { - return ReferenceEquals(leftHandSide, rightHandSide); - } - - if (leftHandSide.Type != rightHandSide.Type) return false; - - if (leftHandSide.IsBoolean) - { - return leftHandSide.Boolean == rightHandSide.Boolean; - } - - if (leftHandSide.IsReal) - { - // ReSharper disable once CompareOfFloatsByEqualityOperator - return leftHandSide.Real == rightHandSide.Real; - } - - if (leftHandSide.IsInteger) - { - return leftHandSide.Integer == rightHandSide.Integer; - } - - if (leftHandSide.IsString) - { - return leftHandSide.String == rightHandSide.String; - } - - if (leftHandSide.IsList) - { - return ListCompare(leftHandSide.List,rightHandSide.List); - } - - if (leftHandSide.IsDictionary) - { - return DictionaryCompare(leftHandSide.Dictionary, rightHandSide.Dictionary); - } - - if (leftHandSide.IsClosure && rightHandSide.IsClosure) - { - return leftHandSide.Closure == rightHandSide.Closure; - } - - return true; - } - private static bool ListCompare(List leftHandSide, List rightHandSide) - { - if (leftHandSide.Count != rightHandSide.Count) - { - return false; - } - return !leftHandSide.Where((t, index) => t != rightHandSide[index]).Any(); - } - - private static bool DictionaryCompare(Dictionary leftHandSide, Dictionary rightHandSide) - { - if (leftHandSide.Count != rightHandSide.Count) - { - return false; - } - - foreach (var kv in leftHandSide) - { - if (rightHandSide.TryGetValue(kv.Key, out var rvalue)) - { - if (kv.Value != rvalue) - { - return false; - } - } - else - { - return false; - } - } - return true; - } - public static bool operator !=(DataValue a, DataValue b) => !(a == b); - - public override bool Equals(object obj) => this == (DataValue)obj; - - public override int GetHashCode() - { - if (IsNone || IsDeletion) - { - return 0; - } - - if (IsBoolean) - { - return Boolean.GetHashCode(); - } - - if (IsInteger) - { - return Integer.GetHashCode(); - } - - if (IsReal) - { - return Real.GetHashCode(); - } - - if (IsString) - { - return String.GetHashCode(); - } - - if (IsList) - { - return List.GetHashCode(); - } - - if (IsDictionary) - { - return Dictionary.GetHashCode(); - } - - if (IsClosure) - { - return Closure.GetHashCode(); - } - - return -1; - } - - public static DataValue operator +(DataValue leftHandSide, DataValue rightHandSide) - { - switch (leftHandSide.Type) - { - case DataType.Real when rightHandSide.IsReal: - return leftHandSide.Real + rightHandSide.Real; - case DataType.Real when rightHandSide.IsInteger: - return leftHandSide.Real + rightHandSide.Integer; - case DataType.Integer when rightHandSide.IsInteger: - return leftHandSide.Integer + rightHandSide.Integer; - case DataType.Integer when rightHandSide.IsReal: - return leftHandSide.Integer + rightHandSide.Real; - case DataType.String when rightHandSide.IsString: - return leftHandSide.String + rightHandSide.String; - case DataType.List when rightHandSide.IsList: - { - // If every value is immutable a shallow copy should be fine - var newList = new List(leftHandSide.List); - newList.AddRange(rightHandSide.List); - return newList; - } - case DataType.None: - case DataType.Boolean: - case DataType.Dictionary: - case DataType.Deletion: - case DataType.Closure: - default: - throw new DataValueOperationException($"Cannot add a {leftHandSide.Type} and a {rightHandSide.Type}"); - } - } - - public static DataValue operator -(DataValue leftHandSide, DataValue rightHandSide) - { - switch (leftHandSide.IsReal) - { - case true when rightHandSide.IsReal: - return leftHandSide.Real - rightHandSide.Real; - case true when rightHandSide.IsInteger: - return leftHandSide.Real - rightHandSide.Integer; - } - - switch (leftHandSide.IsInteger) - { - case true when rightHandSide.IsInteger: - return leftHandSide.Integer - rightHandSide.Integer; - case true when rightHandSide.IsReal: - return leftHandSide.Integer - rightHandSide.Real; - } - - if (leftHandSide.IsList && rightHandSide.IsList) - { - return leftHandSide.List.Where(x => rightHandSide.List.All(y => x != y)).ToList(); - } - - throw new DataValueOperationException($"Cannot subtract a {leftHandSide.Type} and a {rightHandSide.Type}"); - } - - private static DataValue StringRepeat(DataValue str, DataValue amount) - { - StringBuilder sb = new StringBuilder(); - for (var i = 0; i < amount.Integer; i++) - { - sb.Append(str.String); - } - - return sb.ToString(); - } - - private static DataValue ListRepeat(DataValue list, DataValue amount) - { - List newList = []; - for (var i = 0; i < amount.Integer; i++) - { - newList.AddRange(list.List); - } - return newList; - } - - - public static DataValue operator *(DataValue leftHandSide, DataValue rightHandSide) - { - switch (leftHandSide.IsReal) - { - case true when rightHandSide.IsReal: - return leftHandSide.Real * rightHandSide.Real; - case true when rightHandSide.IsInteger: - return leftHandSide.Real * rightHandSide.Integer; - } - - switch (leftHandSide.IsInteger) - { - case true when rightHandSide.IsInteger: - return leftHandSide.Integer * rightHandSide.Integer; - case true when rightHandSide.IsReal: - return leftHandSide.Integer * rightHandSide.Real; - } - - if (leftHandSide.IsString && rightHandSide.IsInteger) - { - return StringRepeat(leftHandSide, rightHandSide); - } - - if (leftHandSide.IsInteger && rightHandSide.IsString) - { - return StringRepeat(rightHandSide, leftHandSide); - } - - if (leftHandSide.IsList && rightHandSide.IsInteger) - { - return ListRepeat(leftHandSide, rightHandSide); - } - - if (leftHandSide.IsInteger && rightHandSide.IsList) - { - return ListRepeat(rightHandSide, leftHandSide); - } - - throw new DataValueOperationException($"Cannot multiply a {leftHandSide.Type} and a {rightHandSide.Type}"); - } - - public static DataValue operator /(DataValue leftHandSide, DataValue rightHandSide) - { - if (leftHandSide.IsReal && rightHandSide.IsReal) - { - return leftHandSide.Real / rightHandSide.Real; - } - - switch (leftHandSide.IsInteger) - { - case true when rightHandSide.IsInteger: - return leftHandSide.Integer / rightHandSide.Integer; - case true when rightHandSide.IsReal: - return leftHandSide.Integer / rightHandSide.Real; - } - - if (leftHandSide.IsReal && rightHandSide.IsInteger) - { - return leftHandSide.Real / rightHandSide.Integer; - } - - throw new DataValueOperationException($"Cannot divide a {leftHandSide.Type} and a {rightHandSide.Type}"); - } - - public static bool operator >(DataValue leftHandSide, DataValue rightHandSide) - { - switch (leftHandSide.IsReal) - { - case true when rightHandSide.IsReal: - return leftHandSide.Real > rightHandSide.Real; - case true when rightHandSide.IsInteger: - return leftHandSide.Real > rightHandSide.Integer; - } - - switch (leftHandSide.IsInteger) - { - case true when rightHandSide.IsInteger: - return leftHandSide.Integer > rightHandSide.Integer; - case true when rightHandSide.IsReal: - return leftHandSide.Integer > rightHandSide.Real; - } - - if (leftHandSide.IsString && rightHandSide.IsString) - { - return string.Compare(leftHandSide.String, rightHandSide.String, StringComparison.Ordinal) > 0; - } - - throw new DataValueOperationException($"Cannot relationally compare a {leftHandSide.Type} and a {rightHandSide.Type}"); - } - - public static bool operator <(DataValue leftHandSide, DataValue rightHandSide) - { - switch (leftHandSide.IsReal) - { - case true when rightHandSide.IsReal: - return leftHandSide.Real < rightHandSide.Real; - case true when rightHandSide.IsInteger: - return leftHandSide.Real < rightHandSide.Integer; - } - - switch (leftHandSide.IsInteger) - { - case true when rightHandSide.IsInteger: - return leftHandSide.Integer < rightHandSide.Integer; - case true when rightHandSide.IsReal: - return leftHandSide.Integer < rightHandSide.Real; - } - - if (leftHandSide.IsString && rightHandSide.IsString) - { - return string.Compare(leftHandSide.String, rightHandSide.String, StringComparison.Ordinal) < 0; - } - - throw new DataValueOperationException($"Cannot relationally compare a {leftHandSide.Type} and a {rightHandSide.Type}"); - } - - public static bool operator >=(DataValue leftHandSide, DataValue rightHandSide) - { - switch (leftHandSide.IsReal) - { - case true when rightHandSide.IsReal: - return leftHandSide.Real >= rightHandSide.Real; - case true when rightHandSide.IsInteger: - return leftHandSide.Real >= rightHandSide.Integer; - } - - switch (leftHandSide.IsInteger) - { - case true when rightHandSide.IsInteger: - return leftHandSide.Integer >= rightHandSide.Integer; - case true when rightHandSide.IsReal: - return leftHandSide.Integer >= rightHandSide.Real; - } - - if (leftHandSide.IsString && rightHandSide.IsString) - { - return string.Compare(leftHandSide.String, rightHandSide.String, StringComparison.Ordinal) >= 0; - } - - throw new DataValueOperationException($"Cannot relationally compare a {leftHandSide.Type} and a {rightHandSide.Type}"); - } - - public static bool operator <=(DataValue leftHandSide, DataValue rightHandSide) - { - switch (leftHandSide.IsReal) - { - case true when rightHandSide.IsReal: - return leftHandSide.Real <= rightHandSide.Real; - case true when rightHandSide.IsInteger: - return leftHandSide.Real <= rightHandSide.Integer; - } - - switch (leftHandSide.IsInteger) - { - case true when rightHandSide.IsInteger: - return leftHandSide.Integer <= rightHandSide.Integer; - case true when rightHandSide.IsReal: - return leftHandSide.Integer <= rightHandSide.Real; - } - - if (leftHandSide.IsString && rightHandSide.IsString) - { - return string.Compare(leftHandSide.String, rightHandSide.String, StringComparison.Ordinal) <= 0; - } - - throw new DataValueOperationException($"Cannot relationally compare a {leftHandSide.Type} and a {rightHandSide.Type}"); - } - - public static DataValue operator %(DataValue leftHandSide, DataValue rightHandSide) => - leftHandSide.IsReal switch - { - true when rightHandSide.IsReal => leftHandSide.Real % rightHandSide.Real, - true when rightHandSide.IsInteger => leftHandSide.Real % rightHandSide.Integer, - _ => leftHandSide.IsInteger switch - { - true when rightHandSide.IsInteger => leftHandSide.Integer % rightHandSide.Integer, - true when rightHandSide.IsReal => leftHandSide.Integer % rightHandSide.Real, - _ => throw new DataValueOperationException( - $"Cannot take the remainder of a {leftHandSide.Type} and a {rightHandSide.Type}") - } - }; - - public static DataValue operator -(DataValue child) - { - if (child.IsInteger) - { - return -child.Integer; - } - - if (child.IsReal) - { - return -child.Real; - } - - throw new DataValueOperationException($"Cannot negate a {child.Type}"); - } - - public static bool operator !(DataValue child) => !child.Truthy; - - public static DataValue operator +(DataValue child) => child; - - public DataValue this[DataValue rightHandSide] - { - get - { - if (IsList && rightHandSide.IsInteger) - { - try - { - return List[(int)rightHandSide.Integer]; - } - catch - { - throw new IndexOutOfRangeException(((int)rightHandSide.Real) + " is out of range of the string being indexed"); - } - } - - if (IsString && rightHandSide.IsInteger) - { - try - { - return (int)String[(int)rightHandSide.Integer]; - } - catch - { - throw new IndexOutOfRangeException(rightHandSide.Integer + " is out of range of the string being indexed"); - } - } - - if (IsDictionary && rightHandSide.IsString) - { - try - { - return Dictionary[rightHandSide.String]; - } - catch - { - throw new KeyNotFoundException(rightHandSide.String + " is not a key found in the dictionary being indexed"); - } - } - - throw new DataValueOperationException( - $"Cannot subscript of a {Type} and a {rightHandSide.Type}"); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/BinaryExpressionTypeException.cs b/src/PatchManager.SassyPatching/Exceptions/BinaryExpressionTypeException.cs deleted file mode 100644 index cf33d0f..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/BinaryExpressionTypeException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -/// -/// An exception thrown when the operands of a binary expression do not match together for the expression -/// -public class BinaryExpressionTypeException : InterpreterException -{ - internal BinaryExpressionTypeException(Coordinate c, string operation, string firstType, string secondType) : base(c,$"Attempting to {operation} a value of type: {firstType} and a value of type: {secondType} which is not allowed") - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/DataValueOperationException.cs b/src/PatchManager.SassyPatching/Exceptions/DataValueOperationException.cs deleted file mode 100644 index 31276c3..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/DataValueOperationException.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -public class DataValueOperationException(string message) : Exception(message) -{ -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/DictionaryKeyNotFoundException.cs b/src/PatchManager.SassyPatching/Exceptions/DictionaryKeyNotFoundException.cs deleted file mode 100644 index 6e65973..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/DictionaryKeyNotFoundException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -/// -/// An exception thrown when a dictionary is indexed with a key that it does not have -/// -public class DictionaryKeyNotFoundException : InterpreterException -{ - internal DictionaryKeyNotFoundException(Coordinate coordinate, string message) : base(coordinate, message) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/FunctionReturnException.cs b/src/PatchManager.SassyPatching/Exceptions/FunctionReturnException.cs deleted file mode 100644 index df312bf..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/FunctionReturnException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -internal class FunctionReturnException : Exception -{ - internal DataValue FunctionResult; - - public FunctionReturnException(DataValue functionResult) - { - FunctionResult = functionResult; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/ImportException.cs b/src/PatchManager.SassyPatching/Exceptions/ImportException.cs deleted file mode 100644 index dafd4ef..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/ImportException.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -internal class ImportException : Exception -{ - -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/IncorrectTypeException.cs b/src/PatchManager.SassyPatching/Exceptions/IncorrectTypeException.cs deleted file mode 100644 index c664d2e..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/IncorrectTypeException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace PatchManager.SassyPatching; - -/// -/// An exception that is thrown when a is read as a type which it is not -/// -public class IncorrectTypeException : Exception -{ - internal IncorrectTypeException(string message) : base(message) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/InterpolationException.cs b/src/PatchManager.SassyPatching/Exceptions/InterpolationException.cs deleted file mode 100644 index ca899e6..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/InterpolationException.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -public class InterpolationException : InterpreterException -{ - internal InterpolationException(Coordinate coordinate, string message) : base(coordinate, message) { } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/InterpreterException.cs b/src/PatchManager.SassyPatching/Exceptions/InterpreterException.cs deleted file mode 100644 index b1aa877..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/InterpreterException.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -/// -/// An exception thrown by the patch interpreter due to runtime code being bad -/// -public class InterpreterException : Exception -{ - /// - /// The location of where the exception was thrown from - /// - public Coordinate Coordinate; - - internal InterpreterException(Coordinate coordinate, string message) : base($"{coordinate.ToString()}: {message}") - { - Coordinate = coordinate; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/InvalidVariableReferenceException.cs b/src/PatchManager.SassyPatching/Exceptions/InvalidVariableReferenceException.cs deleted file mode 100644 index 8332a3b..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/InvalidVariableReferenceException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -/// -/// An exception thrown when a variable is being referenced that does not exist -/// -public class InvalidVariableReferenceException : InterpreterException -{ - internal InvalidVariableReferenceException(Coordinate coordinate, string message) : base(coordinate, message) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/InvocationException.cs b/src/PatchManager.SassyPatching/Exceptions/InvocationException.cs deleted file mode 100644 index 1926642..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/InvocationException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -/// -/// Thrown when invoking a managed function goes awry -/// -public class InvocationException : Exception -{ - internal InvocationException(string message) : base(message) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/ListIndexOutOfRangeException.cs b/src/PatchManager.SassyPatching/Exceptions/ListIndexOutOfRangeException.cs deleted file mode 100644 index bd2e708..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/ListIndexOutOfRangeException.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -public class ListIndexOutOfRangeException : InterpreterException -{ - public ListIndexOutOfRangeException(Coordinate coordinate, string message) : base(coordinate, message) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/NotModifiableException.cs b/src/PatchManager.SassyPatching/Exceptions/NotModifiableException.cs deleted file mode 100644 index 760a8ad..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/NotModifiableException.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -/// -/// Thrown when a selectable is trying to be modified that can't be modified -/// -public class NotModifiableException : Exception -{ - /// - public NotModifiableException(string message) : base(message) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/TypeConversionException.cs b/src/PatchManager.SassyPatching/Exceptions/TypeConversionException.cs deleted file mode 100644 index 039897d..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/TypeConversionException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -/// -/// Thrown by the Managed invoker when a type cannot be converted either way -/// -public class TypeConversionException : Exception -{ - public TypeConversionException(string from, string to) : base($"Cannot convert a value of type {from} to type {to}") - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Exceptions/UnaryTypeException.cs b/src/PatchManager.SassyPatching/Exceptions/UnaryTypeException.cs deleted file mode 100644 index 48b34bc..0000000 --- a/src/PatchManager.SassyPatching/Exceptions/UnaryTypeException.cs +++ /dev/null @@ -1,11 +0,0 @@ -namespace PatchManager.SassyPatching.Exceptions; - -/// -/// An exception thrown when a unary expression is being run on a type that which it cannot -/// -public class UnaryTypeException : InterpreterException -{ - internal UnaryTypeException(Coordinate coordinate, string operation, string firstType) : base(coordinate,$"Attempting to {operation} a value of type: {firstType} which is not allowed") - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/BoundPatchFunction.cs b/src/PatchManager.SassyPatching/Execution/BoundPatchFunction.cs deleted file mode 100644 index bcaa5a4..0000000 --- a/src/PatchManager.SassyPatching/Execution/BoundPatchFunction.cs +++ /dev/null @@ -1,27 +0,0 @@ -namespace PatchManager.SassyPatching.Execution; - -/// -/// A patch function that already has an argument bound to it -/// -public class BoundPatchFunction : PatchFunction -{ - internal readonly PatchFunction InternalFunction; - internal readonly List LeftBindings; - internal readonly List RightBindings; - - internal BoundPatchFunction(PatchFunction internalFunction, List leftBindings, List rightBindings) - { - InternalFunction = internalFunction; - LeftBindings = leftBindings; - RightBindings = rightBindings; - } - - /// - public override DataValue Execute(Environment env, List arguments) - { - var newArgs = new List(LeftBindings); - newArgs.AddRange(arguments); - newArgs.AddRange(RightBindings); - return InternalFunction.Execute(env, newArgs); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/Environment.cs b/src/PatchManager.SassyPatching/Execution/Environment.cs deleted file mode 100644 index d0fac15..0000000 --- a/src/PatchManager.SassyPatching/Execution/Environment.cs +++ /dev/null @@ -1,95 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Nodes; -using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; - -namespace PatchManager.SassyPatching.Execution; - -/// -/// Describes a local environment/scope (per function/patch) used by the patching engine -/// -public class Environment -{ - /// - /// The global environment that this environment is a part of - /// - public GlobalEnvironment GlobalEnvironment; - /// - /// The parent of this scope - /// - [CanBeNull] public readonly Environment Parent; - /// - /// The list of variables in this scope - /// - public Dictionary ScopedValues; - - - [CanBeNull] private List _slotActions; - - [CanBeNull] - public List SlotActions - { - get => _slotActions ?? Parent?.SlotActions; - set => _slotActions = value; - } - - /// - /// Creates a new environment - /// - /// The global environment that this environment will be a part of - /// The parent of the environment - public Environment(GlobalEnvironment globalEnvironment, [CanBeNull] Environment parent = null) - { - GlobalEnvironment = globalEnvironment; - Parent = parent; - ScopedValues = new Dictionary(); - } - - public DataValue this[string index] - { - get - { - if (ScopedValues.TryGetValue(index, out var result)) - { - return result; - } - - if (Parent != null) - { - return Parent[index]; - } - - throw new KeyNotFoundException(index); - } - set - { - if (value.IsDeletion) - { - if (ScopedValues.ContainsKey(index)) - { - ScopedValues.Remove(index); - } - - throw new KeyNotFoundException(index); - } - else - { - ScopedValues[index] = value; - } - } - } - - /// - /// Takes a "snapshot" of this environment, for later action taken within the environment, such as in selection actions - /// - /// A copy of this environment, in its current state, w/ each parent in their current state as well - public Environment Snapshot() - { - var scopedValues = new Dictionary(ScopedValues); - var parent = Parent?.Snapshot(); - return new Environment(GlobalEnvironment, parent) - { - ScopedValues = scopedValues, - _slotActions = _slotActions - }; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/GlobalEnvironment.cs b/src/PatchManager.SassyPatching/Execution/GlobalEnvironment.cs deleted file mode 100644 index aa76b6c..0000000 --- a/src/PatchManager.SassyPatching/Execution/GlobalEnvironment.cs +++ /dev/null @@ -1,71 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Execution; - -/// -/// Describes a global (per patch file) environment used by the sassy patching engine -/// -public class GlobalEnvironment -{ - /// - /// This references the global state that all patches being run share - /// - public Universe Universe; - - /// - /// The Guid of the mod this patch file is from - /// - public string ModGuid; - - public List ImportedLibraries = new(); - - public Dictionary AllFunctions = new(); - - public Dictionary AllMixins = new(); - - - internal GlobalEnvironment(Universe universe, string modGuid) - { - Universe = universe; - ModGuid = modGuid; - } - - internal void Import(Environment rootEnvironment, string libraryName) - { - var fullyQualifiedLibraryName = libraryName.Contains(":") ? libraryName : $"{ModGuid}:{libraryName}"; - if (fullyQualifiedLibraryName.EndsWith(":*")) - { - var baseName = fullyQualifiedLibraryName.Replace(":*", ":"); - var anyFound = false; - foreach (var library in Universe.AllLibraries.Where(library => library.Key.StartsWith(baseName))) - { - anyFound = true; - if (ImportedLibraries.Contains(library.Key)) - { - continue; - } - - library.Value.RegisterInto(rootEnvironment); - ImportedLibraries.Add(library.Key); - } - - if (!anyFound) - { - throw new ImportException(); - } - } else - { - if (ImportedLibraries.Contains(fullyQualifiedLibraryName)) - return; - if (Universe.AllLibraries.TryGetValue(fullyQualifiedLibraryName, out var library)) - { - library.RegisterInto(rootEnvironment); - ImportedLibraries.Add(fullyQualifiedLibraryName); - } - else - { - throw new ImportException(); - } - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/ManagedPatchFunction.cs b/src/PatchManager.SassyPatching/Execution/ManagedPatchFunction.cs deleted file mode 100644 index 6bef957..0000000 --- a/src/PatchManager.SassyPatching/Execution/ManagedPatchFunction.cs +++ /dev/null @@ -1,153 +0,0 @@ -using System.Reflection; -using JetBrains.Annotations; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Execution; - -internal class ManagedPatchFunction : PatchFunction -{ - // private Func,Value> _execute; - private readonly MethodInfo _info; - [CanBeNull] private object _target; - - public ManagedPatchFunction(MethodInfo info, [CanBeNull] object target = null) - { - _info = info; - _target = target; - } - - private static object CheckParameter(ParameterInfo info, DataValue argument) - { - var obj = argument.To(info.ParameterType); - return obj; - } - - public override DataValue Execute(Environment env, List arguments) - { - List args = new(); - - // We are going to consume arguments as we go to prevent errors - - foreach (var parameter in _info.GetParameters()) - { - var argumentName = parameter.Name; - if (parameter.ParameterType.GetCustomAttribute() is { } attribute) - { - argumentName = attribute.ArgumentName; - } - - if (parameter.ParameterType == typeof(Environment)) - { - args.Add(env); - continue; - } - - if (parameter.ParameterType == typeof(GlobalEnvironment)) - { - args.Add(env.GlobalEnvironment); - continue; - } - - if (parameter.ParameterType == typeof(Universe)) - { - args.Add(env.GlobalEnvironment.Universe); - continue; - } - - if (parameter.ParameterType == typeof(List)) - { - args.Add(new List(arguments)); - arguments.Clear(); - continue; - } - - if (parameter.ParameterType == typeof(List) && - parameter.GetCustomAttributes().OfType().Any()) - { - var varArgs = new List(); - var remove = new List(); - for (var i = 0; i < arguments.Count; i++) - { - if (arguments[i].ArgumentName != null) continue; - varArgs.Add(arguments[i].ArgumentDataValue); - remove.Add(i); - } - - args.Add(varArgs); - for (var i = remove.Count - 1; i >= 0; i--) - { - arguments.RemoveAt(i); - } - continue; - } - - if (parameter.ParameterType == typeof(Dictionary) && - parameter.GetCustomAttributes().OfType().Any()) - { - var varArgs = new Dictionary(); - var remove = new List(); - for (var i = 0; i < arguments.Count; i++) - { - if (arguments[i].ArgumentName == null) continue; - varArgs.Add(arguments[i].ArgumentName, arguments[i].ArgumentDataValue); - remove.Add(i); - } - - args.Add(varArgs); - for (var i = remove.Count - 1; i >= 0; i--) - { - arguments.RemoveAt(i); - } - continue; - } - - bool foundPositional = false; - DataValue argument = null; - int removalIndex = -1; - for (int i = 0; i < arguments.Count; i++) - { - if (!foundPositional && arguments[i].ArgumentName == null) - { - foundPositional = true; - removalIndex = i; - argument = arguments[i].ArgumentDataValue; - } - - if (arguments[i].ArgumentName != argumentName) continue; - removalIndex = i; - argument = arguments[i].ArgumentDataValue; - break; - } - - if (removalIndex >= 0) - { - arguments.RemoveAt(removalIndex); - } - - if (argument == null) - { - if (parameter.HasDefaultValue) - { - args.Add(parameter.DefaultValue); - } - else - { - throw new InvocationException($"No value found for argument: {argumentName}"); - } - } - else - { - args.Add(CheckParameter(parameter, argument)); - } - - } - - if (arguments.Count > 0) - { - throw new InvocationException("Too many arguments passed"); - } - - return DataValue.From(_info.Invoke(_target, args.ToArray())); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/ManagedPatchLibrary.cs b/src/PatchManager.SassyPatching/Execution/ManagedPatchLibrary.cs deleted file mode 100644 index 980f4fb..0000000 --- a/src/PatchManager.SassyPatching/Execution/ManagedPatchLibrary.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System.Reflection; -using MonoMod.Utils; -using PatchManager.SassyPatching.Attributes; - -namespace PatchManager.SassyPatching.Execution; - -internal class ManagedPatchLibrary : PatchLibrary -{ - private readonly Dictionary _functions; - private readonly Dictionary _constants; - - public ManagedPatchLibrary(IReflect libraryClass) - { - _functions = libraryClass.GetMethods(BindingFlags.Static | BindingFlags.Public) - .Where(method => method.GetCustomAttributes().OfType().Any()) - .ToDictionary(method => method.GetCustomAttributes().OfType().First().MethodName, - method => new ManagedPatchFunction(method)); - _constants = libraryClass.GetFields(BindingFlags.Static | BindingFlags.Public) - .Where(field => field.GetCustomAttributes().OfType().Any()).ToDictionary( - field => field.GetCustomAttributes().OfType().First().ConstantName, - field => DataValue.From(field.GetValue(null))); - _constants.AddRange(libraryClass.GetProperties(BindingFlags.Static | BindingFlags.Public) - .Where(property => property.GetCustomAttributes().OfType().Any()).ToDictionary( - property => property.GetCustomAttributes().OfType().First().ConstantName, - property => DataValue.From(property.GetValue(null)))); - } - - public override void RegisterInto(Environment environment) - { - foreach (var function in _functions) - { - environment.GlobalEnvironment.Universe.MessageLogger($"Registering function: {function.Key}"); - environment.GlobalEnvironment.AllFunctions[function.Key] = function.Value; - } - - foreach (var constant in _constants) - { - environment.GlobalEnvironment.Universe.MessageLogger($"Registering constant: {constant.Key}"); - environment[constant.Key] = constant.Value; - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/PatchArgument.cs b/src/PatchManager.SassyPatching/Execution/PatchArgument.cs deleted file mode 100644 index 9b6a9e7..0000000 --- a/src/PatchManager.SassyPatching/Execution/PatchArgument.cs +++ /dev/null @@ -1,19 +0,0 @@ -using JetBrains.Annotations; - -namespace PatchManager.SassyPatching.Execution; - -/// -/// This represents an argument passed to a patch function -/// -[PublicAPI] -public class PatchArgument -{ - /// - /// The name of the argument if it was named by the caller - /// - [CanBeNull] public string ArgumentName; - /// - /// The value of the argument - /// - public DataValue ArgumentDataValue; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/PatchFunction.cs b/src/PatchManager.SassyPatching/Execution/PatchFunction.cs deleted file mode 100644 index 285ac5b..0000000 --- a/src/PatchManager.SassyPatching/Execution/PatchFunction.cs +++ /dev/null @@ -1,15 +0,0 @@ -namespace PatchManager.SassyPatching.Execution; - -/// -/// This is the base class for a patcher function be it dll or file based -/// -public abstract class PatchFunction -{ - /// - /// Execute this function - /// - /// The environment this function is being executed in (used mostly for DLL based functions) - /// The list of arguments for the function, the name can be null - /// - public abstract DataValue Execute(Environment env, List arguments); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/PatchLibrary.cs b/src/PatchManager.SassyPatching/Execution/PatchLibrary.cs deleted file mode 100644 index 9b7534a..0000000 --- a/src/PatchManager.SassyPatching/Execution/PatchLibrary.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace PatchManager.SassyPatching.Execution; - -/// -/// This is the base class of a patcher library, either for file or dll libraries, the register into is what is used by the engine to register everything -/// -public abstract class PatchLibrary -{ - /// - /// Register this library into an environment - /// - /// The environment to register it into - public abstract void RegisterInto(Environment environment); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/PatchMixin.cs b/src/PatchManager.SassyPatching/Execution/PatchMixin.cs deleted file mode 100644 index 53868c4..0000000 --- a/src/PatchManager.SassyPatching/Execution/PatchMixin.cs +++ /dev/null @@ -1,87 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Nodes; -using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; -using PatchManager.SassyPatching.Nodes.Statements.TopLevel; - -namespace PatchManager.SassyPatching.Execution; - -public class PatchMixin -{ - public Mixin Function; - - public PatchMixin(Mixin mixin) - { - Function = mixin; - } - - public void Include(Environment env, List arguments, ISelectable selectable, [CanBeNull] IModifiable modifiable) - { - var subEnvironment = new Environment(env.GlobalEnvironment, env); - foreach (var arg in Function.Arguments) - { - ConsumeMixinArgument(arguments, arg, subEnvironment); - } - - if (arguments.Count > 0) - { - throw new InvocationException("Too many arguments have been passed"); - } - foreach (var body in Function.Body) - { - if (body is ISelectionAction selectionAction) - { - selectionAction.ExecuteOn(subEnvironment, selectable, modifiable); - } - else - { - body.ExecuteIn(subEnvironment); - } - } - - } - - private static void ConsumeMixinArgument(List arguments, Argument arg, Environment subEnvironment) - { - // As per usual we consume - var foundPositional = false; - DataValue argument = null; - var removalIndex = -1; - for (var i = 0; i < arguments.Count; i++) - { - if (!foundPositional && arguments[i].ArgumentName == null) - { - foundPositional = true; - removalIndex = i; - argument = arguments[i].ArgumentDataValue; - } - - if (arguments[i].ArgumentName != arg.Name) continue; - removalIndex = i; - argument = arguments[i].ArgumentDataValue; - break; - } - - if (removalIndex >= 0) - { - arguments.RemoveAt(removalIndex); - } - if (argument == null) - { - if (arg.Value != null) - { - subEnvironment[arg.Name] = arg.Value.Compute(subEnvironment); - } - else - { - throw new InvocationException($"No value found for argument: {arg.Name}"); - } - } - else - { - // args.Add(CheckParameter(parameter, argument)); - subEnvironment[arg.Name] = argument; - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/SassyGenerator.cs b/src/PatchManager.SassyPatching/Execution/SassyGenerator.cs deleted file mode 100644 index 45d35cf..0000000 --- a/src/PatchManager.SassyPatching/Execution/SassyGenerator.cs +++ /dev/null @@ -1,51 +0,0 @@ -using PatchManager.SassyPatching.Nodes.Attributes; -using PatchManager.SassyPatching.Nodes.Statements; -using PatchManager.Shared.Interfaces; - -namespace PatchManager.SassyPatching.Execution; - -public class SassyGenerator : ITextAssetGenerator -{// This is a snapshot of the environment before the patch was registered, note it will still reference the same global environment as its file, as that is only mutated by function declarations - // Same w/ universe environment, as that should only contain stage definitions and such - private Environment _environmentSnapshot; - private SelectionBlock _rootSelectionBlock; - private List _arguments; - - internal SassyGenerator(Environment environmentSnapshot, SelectionBlock rootSelectionBlock, List arguments) - { - _environmentSnapshot = environmentSnapshot; - _rootSelectionBlock = rootSelectionBlock; - _arguments = arguments; - var stage = rootSelectionBlock.Attributes.OfType().FirstOrDefault(); - if (stage == null) - { - Priority = ulong.MaxValue; - } - else - { - var global = environmentSnapshot.GlobalEnvironment; - string stageName; - if (stage.Stage.Contains(':')) - { - stageName = stage.Stage; - } - else - { - stageName = global.ModGuid + ":" + stage.Stage; - } - - // If this errors then we don't register the patch, but we should give a more friendly thing to this at some point - Priority = global.Universe.AllStages[stageName]; - } - } - - /// - public ulong Priority { get; } - public string Create(out string label, out string name) - { - var val = _rootSelectionBlock.ExecuteCreation(_environmentSnapshot, _arguments); - label = val.Label; - name = val.Name; - return val.Text; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/SassyPatchClosure.cs b/src/PatchManager.SassyPatching/Execution/SassyPatchClosure.cs deleted file mode 100644 index 22998c5..0000000 --- a/src/PatchManager.SassyPatching/Execution/SassyPatchClosure.cs +++ /dev/null @@ -1,81 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Nodes.Expressions; - -namespace PatchManager.SassyPatching.Execution; - -internal class SassyPatchClosure : PatchFunction -{ - public Environment Snapshot; - public Closure Function; - - public SassyPatchClosure(Environment snapshot, Closure function) - { - Snapshot = snapshot; - Function = function; - } - - public override DataValue Execute(Environment env, List arguments) - { - Environment subEnvironment = new Environment(Snapshot.GlobalEnvironment, Snapshot); - foreach (var arg in Function.Arguments) - { - // As per usual we consume - bool foundPositional = false; - DataValue argument = null; - int removalIndex = -1; - for (int i = 0; i < arguments.Count; i++) - { - if (!foundPositional && arguments[i].ArgumentName == null) - { - foundPositional = true; - removalIndex = i; - argument = arguments[i].ArgumentDataValue; - } - - if (arguments[i].ArgumentName != arg.Name) continue; - removalIndex = i; - argument = arguments[i].ArgumentDataValue; - break; - } - - if (removalIndex >= 0) - { - arguments.RemoveAt(removalIndex); - } - if (argument == null) - { - if (arg.Value != null) - { - subEnvironment[arg.Name] = arg.Value.Compute(subEnvironment); - } - else - { - throw new InvocationException($"No value found for argument: {arg.Name}"); - } - } - else - { - // args.Add(CheckParameter(parameter, argument)); - subEnvironment[arg.Name] = argument; - } - } - - if (arguments.Count > 0) - { - throw new InvocationException("Too many arguments have been passed"); - } - try - { - foreach (var body in Function.Body) - { - body.ExecuteIn(subEnvironment); - } - } - catch (FunctionReturnException ret) - { - return ret.FunctionResult; - } - - return new DataValue(DataValue.DataType.None); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/SassyPatchFunction.cs b/src/PatchManager.SassyPatching/Execution/SassyPatchFunction.cs deleted file mode 100644 index 202a0da..0000000 --- a/src/PatchManager.SassyPatching/Execution/SassyPatchFunction.cs +++ /dev/null @@ -1,81 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Nodes.Statements.TopLevel; - -namespace PatchManager.SassyPatching.Execution; - -internal class SassyPatchFunction : PatchFunction -{ - public Environment Snapshot; - public Function Function; - - public SassyPatchFunction(Environment snapshot, Function function) - { - Snapshot = snapshot; - Function = function; - } - - public override DataValue Execute(Environment env, List arguments) - { - Environment subEnvironment = new Environment(Snapshot.GlobalEnvironment, Snapshot); - foreach (var arg in Function.Arguments) - { - // As per usual we consume - bool foundPositional = false; - DataValue argument = null; - int removalIndex = -1; - for (int i = 0; i < arguments.Count; i++) - { - if (!foundPositional && arguments[i].ArgumentName == null) - { - foundPositional = true; - removalIndex = i; - argument = arguments[i].ArgumentDataValue; - } - - if (arguments[i].ArgumentName != arg.Name) continue; - removalIndex = i; - argument = arguments[i].ArgumentDataValue; - break; - } - - if (removalIndex >= 0) - { - arguments.RemoveAt(removalIndex); - } - if (argument == null) - { - if (arg.Value != null) - { - subEnvironment[arg.Name] = arg.Value.Compute(subEnvironment); - } - else - { - throw new InvocationException($"No value found for argument: {arg.Name}"); - } - } - else - { - // args.Add(CheckParameter(parameter, argument)); - subEnvironment[arg.Name] = argument; - } - } - - if (arguments.Count > 0) - { - throw new InvocationException("Too many arguments have been passed"); - } - try - { - foreach (var body in Function.Body) - { - body.ExecuteIn(subEnvironment); - } - } - catch (FunctionReturnException ret) - { - return ret.FunctionResult; - } - - return new DataValue(DataValue.DataType.None); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/SassyPatchLibrary.cs b/src/PatchManager.SassyPatching/Execution/SassyPatchLibrary.cs deleted file mode 100644 index 435d294..0000000 --- a/src/PatchManager.SassyPatching/Execution/SassyPatchLibrary.cs +++ /dev/null @@ -1,18 +0,0 @@ -using PatchManager.SassyPatching.Nodes; - -namespace PatchManager.SassyPatching.Execution; - -internal class SassyPatchLibrary : PatchLibrary -{ - public SassyPatch Patch; - - public SassyPatchLibrary(SassyPatch patch) - { - Patch = patch; - } - - public override void RegisterInto(Environment environment) - { - Patch.ExecuteIn(environment); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/SassyTextPatcher.cs b/src/PatchManager.SassyPatching/Execution/SassyTextPatcher.cs deleted file mode 100644 index 33411ff..0000000 --- a/src/PatchManager.SassyPatching/Execution/SassyTextPatcher.cs +++ /dev/null @@ -1,62 +0,0 @@ -using PatchManager.SassyPatching.Nodes.Attributes; -using PatchManager.SassyPatching.Nodes.Statements; -using PatchManager.Shared.Interfaces; - -namespace PatchManager.SassyPatching.Execution; - -/// -/// This is the class that all sassy patches get converted to -/// -public class SassyTextPatcher : ITextPatcher -{ - - // This is a snapshot of the environment before the patch was registered, note it will still reference the same global environment as its file, as that is only mutated by function declarations - // Same w/ universe environment, as that should only contain stage definitions and such - private Environment _environmentSnapshot; - private SelectionBlock _rootSelectionBlock; - - internal SassyTextPatcher(Environment environmentSnapshot, SelectionBlock rootSelectionBlock) - { - _environmentSnapshot = environmentSnapshot; - _rootSelectionBlock = rootSelectionBlock; - // var stage = rootSelectionBlock.Attributes.OfType().FirstOrDefault(); - // if (stage == null) - // { - // Priority = ulong.MaxValue; - // } - // else - // { - // var global = environmentSnapshot.GlobalEnvironment; - // string stageName; - // if (stage.Stage.Contains(':')) - // { - // stageName = stage.Stage; - // } - // else - // { - // stageName = global.ModGuid + ":" + stage.Stage; - // } - // - // // If this errors then we don't register the patch, but we should give a more friendly thing to this at some point - // Priority = global.Universe.AllStages[stageName]; - // } - OriginalGuid = environmentSnapshot.GlobalEnvironment.ModGuid; - PriorityString = - rootSelectionBlock.Attributes.OfType().FirstOrDefault() is { } runAtStageAttribute - ? runAtStageAttribute.Stage.Interpolate(environmentSnapshot) - : environmentSnapshot.GlobalEnvironment.ModGuid; - - } - - public string OriginalGuid { get; } - public string PriorityString { get; } - - /// - public ulong Priority { get; set; } - - /// - public bool TryPatch(string patchType, string name, ref string patchData) - { - return _rootSelectionBlock.ExecuteFresh(_environmentSnapshot,patchType, name, ref patchData); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/SelectableWithEnvironment.cs b/src/PatchManager.SassyPatching/Execution/SelectableWithEnvironment.cs deleted file mode 100644 index 2097143..0000000 --- a/src/PatchManager.SassyPatching/Execution/SelectableWithEnvironment.cs +++ /dev/null @@ -1,19 +0,0 @@ -using PatchManager.SassyPatching.Interfaces; - -namespace PatchManager.SassyPatching.Execution; - -/// -/// Used to store information in a selectable, for stuff like class capture selectors and the like -/// Makes stuff a lot more complex, but meh -/// -public class SelectableWithEnvironment -{ - /// - /// The selectable being selected against - /// - public ISelectable Selectable; - /// - /// The environment being used - /// - public Environment Environment; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/Stage.cs b/src/PatchManager.SassyPatching/Execution/Stage.cs deleted file mode 100644 index f1efd73..0000000 --- a/src/PatchManager.SassyPatching/Execution/Stage.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace PatchManager.SassyPatching.Execution; - -public class Stage -{ - public List RunsBefore = new(); - public List RunsAfter = new(); - - - public void UpdateRequirements(List allStages) - { - RunsBefore = RunsBefore.Where(x => allStages.Contains(x)).ToList(); - RunsAfter = RunsAfter.Where(x => allStages.Contains(x)).ToList(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Execution/Universe.cs b/src/PatchManager.SassyPatching/Execution/Universe.cs deleted file mode 100644 index 1f17608..0000000 --- a/src/PatchManager.SassyPatching/Execution/Universe.cs +++ /dev/null @@ -1,467 +0,0 @@ -using Antlr4.Runtime; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Nodes; -using PatchManager.Shared.Interfaces; -using SassyPatchGrammar; -using System.Reflection; -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Nodes.Expressions; -using PatchManager.Shared; - -namespace PatchManager.SassyPatching.Execution; - -/// -/// The state that all executing patches share -/// -public class Universe -{ - /// - /// This contains all rule sets that have been found in all assemblies - /// - public static readonly Dictionary RuleSets; - - /// - /// This contains all the managed libraries that have been found in all assemblies - /// - public static readonly Dictionary AllManagedLibraries; - - private static List _preloadedLabels; - - static Universe() - { - RuleSets = new(); - AllManagedLibraries = new(); - _preloadedLabels = new(); - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - // Only use public rule sets - foreach (var type in assembly.GetTypes()) - { - if (type.IsAbstract || type.IsInterface) continue; - if (typeof(IPatcherRuleSet).IsAssignableFrom(type)) - { - var rsAttribute = type.GetCustomAttribute(); - if (rsAttribute != null) - { - RuleSets[rsAttribute.RulesetName] = (IPatcherRuleSet)Activator.CreateInstance(type); - _preloadedLabels.AddRange(rsAttribute.PreloadLabels); - } - } - - var sassyLibraryAttribute = type.GetCustomAttribute(); - if (sassyLibraryAttribute != null) - { - var name = sassyLibraryAttribute.Mod + ":" + sassyLibraryAttribute.Library; - AllManagedLibraries[name] = new ManagedPatchLibrary(type); - Console.WriteLine($"Registered a managed library, {name}"); - } - } - } - } - - - public Dictionary> Configs = new(); -#nullable enable - public List<(long priority, string label, string? name, Expression updateExpression, Environment snapshot)> ConfigUpdates = new(); - public void AddConfigUpdater(long priority, string label, string? name, Expression updateExpression, Environment snapshot) - { - if (ConfigUpdates.Count == 0) - { - ConfigUpdates.Add((priority, label, name, updateExpression,snapshot)); - return; - } - - for (var i = 0; i < ConfigUpdates.Count; i++) - { - if (ConfigUpdates[i].priority < priority) continue; - - ConfigUpdates.Insert(i,(priority, label, name, updateExpression,snapshot)); - return; - } - ConfigUpdates.Add((priority, label, name, updateExpression,snapshot)); - } -#nullable disable - /// - /// All stages defined by every mod - /// - public Dictionary AllStages = new(); - - // Populated from Space Warps mod list come 1.3.0 - public List AllMods; - - /// - /// This is an action that is taken - /// - public readonly Action RegisterPatcher; - - - /// - /// Register a generator patch - /// - public readonly Action RegisterGenerator; - - /// - /// This logs errors in this universe - /// - private readonly Action _errorLogger; - - - /// - /// The list of labels that this universe needs loaded to respond to - /// - public List LoadedLabels; - - /// - /// This logs any message that is not an error in the universe - /// - public readonly Action MessageLogger; - - private readonly List<(string id, SassyPatch patch)> _toRegister = new(); - - /// - /// Create a new universal state - /// - /// This action receives patchers and registers them for later execution - /// The action to be taken to log an error - /// The action to be taken to log a message - public Universe(Action registerPatcher, Action errorLogger, Action messageLogger, Action registerGenerator, List allMods) - { - RegisterPatcher = registerPatcher; - _errorLogger = errorLogger; - MessageLogger = messageLogger; - RegisterGenerator = registerGenerator; - LoadedLabels = new List(_preloadedLabels); - AllMods = allMods; - MessageLogger("Setup universe!"); - SetupBasePriorities(allMods); - } - - // TODO: Fix this so that other mods stages get their guids working - /// - /// All the libraries in this "universe" - /// - public readonly Dictionary AllLibraries = new(AllManagedLibraries); - - private class LoadException : Exception - { - public LoadException(string message) : base(message) - { - } - } - - internal class ParserListener : IAntlrErrorListener - { - internal bool Errored; - internal Action ErrorLogger; - internal string File; - internal ParserListener(string file, Action errorLogger) - { - File = file; - ErrorLogger = errorLogger; - } - - public void SyntaxError(TextWriter output, IRecognizer recognizer, IToken offendingSymbol, int line, - int charPositionInLine, - string msg, RecognitionException e) - { - Errored = true; - ErrorLogger.Invoke($"error parsing {File} - {line}:{charPositionInLine}: {msg}"); - } - } - - internal class LexerListener : IAntlrErrorListener - { - internal bool Errored; - internal Action ErrorLogger; - internal string File; - internal LexerListener(string file, Action errorLogger) - { - File = file; - ErrorLogger = errorLogger; - } - - public void SyntaxError(TextWriter output, IRecognizer recognizer, int offendingSymbol, int line, - int charPositionInLine, - string msg, RecognitionException e) - { - Errored = true; - ErrorLogger.Invoke($"error lexing {File} - {line}:{charPositionInLine}: {msg}"); - } - } - /// - /// Loads all patches from a directory - /// - /// - /// The ID of the mod to load the guid as - public void LoadPatchesInDirectory(DirectoryInfo directory, string modId) - { - // MessageLogger.Invoke($"Loading patches from {directory} (modId: {modId})"); - var tokenTransformer = new Transformer(msg => throw new LoadException(msg)); - foreach (var library in directory.EnumerateFiles("_*.patch", SearchOption.AllDirectories)) - { - LoadSingleLibrary(modId, library, tokenTransformer); - } - - foreach (var patch in directory.EnumerateFiles("*.patch", SearchOption.AllDirectories)) - { - LoadSinglePatch(modId, patch, tokenTransformer); - } - } - - /// - /// Loads a single patch - /// - /// The file info of the patch file - /// The working directory to generate the patch mod id against - public void LoadSinglePatchFile(FileInfo patch, DirectoryInfo cwd) - { - var tokenTransformer = new Transformer(msg => throw new LoadException(msg)); - var name = Path.GetFileNameWithoutExtension(patch.FullName); - var id = patch.Directory!.FullName.MakeRelativePathTo(cwd.FullName).Replace("\\", "-"); - if (name.StartsWith("_")) - { - LoadSingleLibrary(id, patch, tokenTransformer); - } - else - { - LoadSinglePatch(id, patch, tokenTransformer); - } - } - - private void LoadSinglePatch(string modId, FileInfo patch, Transformer tokenTransformer) - { - if (patch.Name.StartsWith("_")) - return; - try - { - MessageLogger.Invoke($"Loading patch {modId}:{patch.Name}"); - var charStream = CharStreams.fromPath(patch.FullName); - var lexer = new sassy_lexer(charStream); - var lexerErrorGenerator = new LexerListener($"{modId}:{patch.Name}", _errorLogger); - lexer.AddErrorListener(lexerErrorGenerator); - if (lexerErrorGenerator.Errored) - throw new LoadException("lexer errors detected"); - var tokenStream = new CommonTokenStream(lexer); - var parser = new sassy_parser(tokenStream); - var parserErrorGenerator = new ParserListener($"{modId}:{patch.Name}", _errorLogger); - parser.AddErrorListener(parserErrorGenerator); - var patchContext = parser.patch(); - if (parserErrorGenerator.Errored) - throw new LoadException("parser errors detected"); - tokenTransformer.Errored = false; - // var gEnv = new GlobalEnvironment(this, modId); - // var env = new Environment(gEnv); - var ctx = tokenTransformer.Visit(patchContext) as SassyPatch; - _toRegister.Add((modId, ctx)); - // lib = new SassyPatchLibrary(patch); - } - catch (Exception e) - { - _errorLogger($"Could not run patch: {modId}:{patch.Name} due to: {e}"); - } - } - - private void LoadSingleLibrary(string modId, FileInfo library, Transformer tokenTransformer) - { - string name = modId + ":" + library.Name.Replace(".patch", "").TrimFirst(); - try - { - MessageLogger.Invoke($"Loading library {name}"); - var charStream = CharStreams.fromPath(library.FullName); - var lexerErrorGenerator = new LexerListener(name, _errorLogger); - var lexer = new sassy_lexer(charStream); - lexer.AddErrorListener(lexerErrorGenerator); - if (lexerErrorGenerator.Errored) - throw new LoadException("lexer errors detected"); - var tokenStream = new CommonTokenStream(lexer); - var parser = new sassy_parser(tokenStream); - var parserErrorGenerator = new ParserListener(name, _errorLogger); - parser.AddErrorListener(parserErrorGenerator); - if (parserErrorGenerator.Errored) - throw new LoadException("parser errors detected"); - var patchContext = parser.patch(); - tokenTransformer.Errored = false; - var patch = tokenTransformer.Visit(patchContext) as SassyPatch; - var lib = new SassyPatchLibrary(patch); - AllLibraries[name] = lib; - } - catch (Exception e) - { - _errorLogger($"Could not load library: {name} due to: {e.Message}"); - } - } - - public List SassyTextPatchers = new(); - public void RegisterPatcherToUniverse(SassyTextPatcher sassyTextPatcher) - { - SassyTextPatchers.Add(sassyTextPatcher); - } - - /// - /// This registers every patch in the files in the to register list - /// - public void RegisterAllPatches() - { - foreach (var (modId, patch) in _toRegister) - { - var gEnv = new GlobalEnvironment(this, modId); - var env = new Environment(gEnv); - patch.ExecuteIn(env); - } - - // Now we get to do the fun stuff with stages - foreach (var stage in UnsortedStages.Values) - stage.UpdateRequirements(UnsortedStages.Keys.ToList()); - SortStages(); - // Now lets update configs - foreach (var (_,label,name,updateExpression,environment) in ConfigUpdates) - { - var interpLabel = label.Interpolate(environment); - if (!Configs.TryGetValue(interpLabel, out var labelDict)) - labelDict = Configs[interpLabel] = new Dictionary(); - var subEnv = new Environment(environment.GlobalEnvironment,environment); - if (name != null) - { - var interpName = name.Interpolate(environment); - if (labelDict.TryGetValue(interpName, out var toAddValue)) - { - subEnv["value"] = toAddValue; - } - else - { - subEnv["value"] = labelDict[interpName] = new DataValue(DataValue.DataType.None); - } - - var result = updateExpression.Compute(subEnv); - if (result.IsDeletion) - { - labelDict.Remove(name); - } - else - { - labelDict[interpName] = result; - } - } - else - { - subEnv["value"] = DataValue.From(labelDict); - var result = updateExpression.Compute(subEnv); - if (result.IsDeletion) - { - labelDict.Clear(); - } - else if (!result.IsDictionary) - { - throw new InterpreterException(updateExpression.Coordinate, - "Updating a config label must result in a dictionary or deletion value."); - } - else - { - Configs[label] = result.Dictionary; - } - } - } - - foreach (var patcher in SassyTextPatchers) - { - var stage = patcher.PriorityString; - var modId = patcher.OriginalGuid; - if (AllStages.TryGetValue(stage, out var priority)) - { - patcher.Priority = priority; - } else if (AllStages.TryGetValue($"{modId}:{stage}", out priority)) - { - patcher.Priority = priority; - } else if (AllStages.TryGetValue(modId, out priority)) - { - patcher.Priority = priority; - } - - RegisterPatcher(patcher); - } - } - - private void SortStages() - { - MessageLogger($"Sorting {UnsortedStages.Count} stages"); - List sortedStages = new(); - Dictionary toSort = new(UnsortedStages); - while (toSort.Count > 0) - { - if (!SingleSortStep(toSort, sortedStages)) - { - throw new Exception( - $"Unable to sort stages to define patch order, the following stages cause a circular dependency: {string.Join(", ", toSort.Keys)}"); - } - } - - // For debug purposes - MessageLogger("Sorted stages!"); - ulong n = 0; - foreach (var stage in sortedStages) - { - MessageLogger($"{stage}: {n}"); - AllStages[stage] = n++; - } - } - - - private static bool SingleSortStep( - Dictionary toBeSorted, - List sortedStages - ) - { - var remove = ""; - var found = false; - foreach (var (name, stage) in toBeSorted) - { - if (!stage.RunsAfter.All(sortedStages.Contains) || toBeSorted.Values.Any(x => x.RunsBefore.Contains(name))) - { - continue; - } - - remove = name; - found = true; - sortedStages.Add(name); - break; - } - - if (found) - { - toBeSorted.Remove(remove); - } - return found; - } - - public void PatchLabels(params string[] labels) - { - LoadedLabels.AddRange(labels); - } - - public readonly Dictionary UnsortedStages = new(); - public readonly Dictionary LastImplicitWithinMod = new(); - public string LastImplicitGlobal = ""; - - private void SetupBasePriorities(List modLoadOrder) - { - MessageLogger($"Setting up base priorities with mod load order: {string.Join(", ", modLoadOrder)}"); - var lastPost = ""; - foreach (var mod in modLoadOrder) - { - var stage = new Stage(); - if (lastPost.Length > 0) - stage.RunsAfter.Add(lastPost); - UnsortedStages[mod] = stage; - MessageLogger($"Adding stage: {mod}"); - var post = new Stage(); - post.RunsAfter.Add(mod); - lastPost = $"{mod}:post"; - UnsortedStages[lastPost] = post; - MessageLogger($"Adding stage: {lastPost}"); - LastImplicitWithinMod[mod] = mod; - } - LastImplicitGlobal = lastPost; - MessageLogger($"Last implicit global: {lastPost}"); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Interfaces/IModifiable.cs b/src/PatchManager.SassyPatching/Interfaces/IModifiable.cs deleted file mode 100644 index 22bc3ab..0000000 --- a/src/PatchManager.SassyPatching/Interfaces/IModifiable.cs +++ /dev/null @@ -1,37 +0,0 @@ -namespace PatchManager.SassyPatching.Interfaces; - -/// -/// Represents a modifiable value -/// -public interface IModifiable -{ - /// - /// Gets the value of a field - /// - /// The name of the field - /// The value of the field - public DataValue GetFieldValue(string fieldName); - /// - /// Sets the value of a field - /// - /// The name of the field - /// The value to set it to - public void SetFieldValue(string fieldName, DataValue dataValue); - - /// - /// Set this object to another value - /// - /// The value to set it to - public void Set(DataValue dataValue); - - /// - /// Get the value of this object - /// - /// The value of the object - public DataValue Get(); - - /// - /// Finalize modification of this object, and close its modification - /// - public void Complete(); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Interfaces/INewAsset.cs b/src/PatchManager.SassyPatching/Interfaces/INewAsset.cs deleted file mode 100644 index c54b115..0000000 --- a/src/PatchManager.SassyPatching/Interfaces/INewAsset.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace PatchManager.SassyPatching.Interfaces; - -/// -/// Represents a new asset being created -/// -public interface INewAsset -{ - public string Label { get; } - public string Name { get; } - public string Text { get; } - - public ISelectable Selectable { get; } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Interfaces/IPatcherRuleSet.cs b/src/PatchManager.SassyPatching/Interfaces/IPatcherRuleSet.cs deleted file mode 100644 index 5182056..0000000 --- a/src/PatchManager.SassyPatching/Interfaces/IPatcherRuleSet.cs +++ /dev/null @@ -1,33 +0,0 @@ -namespace PatchManager.SassyPatching.Interfaces; - - -// Essentially the ruleset requires ISelectable -/// -/// A ruleset for the patcher (the ":..." selectors) -/// -public interface IPatcherRuleSet -{ - /// - /// What type of patch type will this ruleset match - /// - /// The label to match - /// True if the label matches the ruleset - public bool Matches(string label); - - /// - /// This converts json data to an ISelectable for the rest of the engine to use - /// - /// The type of data to convert to an ISelectale - /// The name of the data - /// The data to convert to an ISelectable - /// The selectable representing the data - public ISelectable ConvertToSelectable(string type, string name, string jsonData); - - - /// - /// Creates a new asset for the patcher - /// - /// The data values to create the asset from - /// The new asset - public INewAsset CreateNew(List dataValues); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Interfaces/ISelectable.cs b/src/PatchManager.SassyPatching/Interfaces/ISelectable.cs deleted file mode 100644 index 1ef99ef..0000000 --- a/src/PatchManager.SassyPatching/Interfaces/ISelectable.cs +++ /dev/null @@ -1,70 +0,0 @@ -namespace PatchManager.SassyPatching.Interfaces; - -/// -/// Represents a selectable object -/// -public interface ISelectable -{ - /// - /// Select all children - /// - /// All children - public List SelectEverything(); - - /// - /// Test if this selectable matches a name pattern - /// - /// The pattern being matched against - /// True if it matches the name pattern - public bool MatchesName(string name); - /// - /// Test if this selectable has a class - /// - /// The class - /// True if it has the class - public bool MatchesClass(string @class); - - /// - /// Get the value for a class - /// - public bool MatchesClass(string @class, out DataValue classValue); - - - /// - /// Test if this selectable is an element - /// - /// The element - /// True if it is the element - public bool MatchesElement(string element); - - /// - /// Checks if this selectable is the same as another selectable - /// - /// The selectable to be checked against - /// True if they are the same - public bool IsSameAs(ISelectable other); - - /// - /// Opens up this selectable for modification - /// - /// The modifiable state of this selector or null if not modifiable - public IModifiable OpenModification(); - - /// - /// Adds an element to this selectable and returns the selectable for it - /// - /// Thrown if this selectable cannot be modified - public ISelectable AddElement(string elementType); - - /// - /// Convert the ISelectable back to its string form, used to finalize a patch - /// - /// A string representing all the data contained in the ISelectable, usually in JSON - public string Serialize(); - - /// - /// Converts the selectable into a DataValue - /// - /// The value representation of the selectable - public DataValue GetValue(); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Modifiables/CustomJTokenModifiable.cs b/src/PatchManager.SassyPatching/Modifiables/CustomJTokenModifiable.cs deleted file mode 100644 index a959cf9..0000000 --- a/src/PatchManager.SassyPatching/Modifiables/CustomJTokenModifiable.cs +++ /dev/null @@ -1,107 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching.Interfaces; -// ReSharper disable CognitiveComplexity - -namespace PatchManager.SassyPatching.Modifiables; - -public abstract class CustomJTokenModifiable : IModifiable -{ - /// - /// This is the data stored w/in this modifiable strucure - /// - protected readonly JToken JToken; - private readonly Action _setDirty; - - /// - /// Deletes a token, or if its a property, its parent - /// - /// - private static void RemoveToken(JToken token) - { - if (token.Parent is JProperty) - { - token.Parent.Remove(); - } - else - { - token.Remove(); - } - } - - /// - /// - /// - /// - /// - protected CustomJTokenModifiable(JToken jToken, Action setDirty) - { - JToken = jToken; - _setDirty = setDirty; - } - - /// - /// Sets a JToken to a value, taking care of deletions - /// - /// The JToken being set or replaced - /// The Value to replace it with - protected static void Set(JToken jToken, DataValue dataValue) - { - if (dataValue.IsDeletion) - { - RemoveToken(jToken); - } - else - { - jToken.Replace(dataValue.ToJToken()); - } - } - - /// - public virtual DataValue GetFieldValue(string fieldName) - { - try - { - return DataValue.FromJToken(JToken[fieldName]); - } - catch - { - return new DataValue(DataValue.DataType.None); - } - } - - /// - public virtual void SetFieldValue(string fieldName, DataValue dataValue) - { - _setDirty(); - if (dataValue.IsDeletion) - { - if (JToken is JObject obj && obj.ContainsKey(fieldName)) - JToken[fieldName]!.Remove(); - } - else - { - if (JToken is JObject obj && !obj.ContainsKey(fieldName)) - JToken[fieldName] = dataValue.ToJToken(); - else - JToken[fieldName]!.Replace(dataValue.ToJToken()); - } - } - - /// - public virtual void Set(DataValue dataValue) - { - _setDirty(); - Set(JToken, dataValue); - } - - /// - public virtual DataValue Get() - { - return DataValue.FromJToken(JToken); - } - - /// - public virtual void Complete() - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Modifiables/JTokenModifiable.cs b/src/PatchManager.SassyPatching/Modifiables/JTokenModifiable.cs deleted file mode 100644 index 9ad5b9d..0000000 --- a/src/PatchManager.SassyPatching/Modifiables/JTokenModifiable.cs +++ /dev/null @@ -1,86 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching.Interfaces; - -namespace PatchManager.SassyPatching.Modifiables; - -public class JTokenModifiable : IModifiable -{ - private JToken _jToken; - private readonly Action _setDirty; - - private static void RemoveToken(JToken token) - { - if (token.Parent is JProperty) - { - token.Parent.Remove(); - } - else - { - token.Remove(); - } - } - - public JTokenModifiable(JToken jToken, Action setDirty) - { - _jToken = jToken; - this._setDirty = setDirty; - } - - public DataValue GetFieldValue(string fieldName) - { - try - { - return DataValue.FromJToken(_jToken[fieldName]); - } - catch - { - return DataValue.Null; - } - } - - public void SetFieldValue(string fieldName, DataValue dataValue) - { - _setDirty(); - if (dataValue.IsDeletion) - { - if (_jToken[fieldName].Parent is JProperty jProperty) - { - jProperty.Remove(); - } - else - { - _jToken[fieldName].Remove(); - } - } - else - { - if (_jToken is JObject obj && !obj.ContainsKey(fieldName)) - _jToken[fieldName] = dataValue.ToJToken(); - else - _jToken[fieldName].Replace(dataValue.ToJToken()); - } - } - - public virtual void Set(DataValue dataValue) - { - _setDirty(); - if (dataValue.IsDeletion) - { - // _jToken.Remove(); - RemoveToken(_jToken); - } - else - { - _jToken.Replace(dataValue.ToJToken()); - } - } - - public DataValue Get() - { - return DataValue.FromJToken(_jToken); - } - - public void Complete() - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/NewAssets/NewGenericAsset.cs b/src/PatchManager.SassyPatching/NewAssets/NewGenericAsset.cs deleted file mode 100644 index 64751c9..0000000 --- a/src/PatchManager.SassyPatching/NewAssets/NewGenericAsset.cs +++ /dev/null @@ -1,34 +0,0 @@ -using PatchManager.SassyPatching.Interfaces; - -namespace PatchManager.SassyPatching.NewAssets; - -/// -/// Represents a newly made generic asset -/// -public class NewGenericAsset : INewAsset -{ - /// - /// Create a descriptor for a new asset - /// - /// The label of the asset - /// The name of the asset - /// the selectable of the asset - public NewGenericAsset(string label, string name, ISelectable selectable) - { - Label = label; - Name = name; - Selectable = selectable; - } - - /// - public string Label { get; } - - /// - public string Name { get; } - - /// - public string Text => Selectable.Serialize(); - - /// - public ISelectable Selectable { get; } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Argument.cs b/src/PatchManager.SassyPatching/Nodes/Argument.cs deleted file mode 100644 index 6454cd1..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Argument.cs +++ /dev/null @@ -1,31 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Nodes.Expressions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes; - -/// -/// Represents an argument definition for a function/mixin -/// -public class Argument : Node -{ - /// - /// The name of the argument being defined - /// - public readonly string Name; - /// - /// The default value of the argument if there is one - /// - [CanBeNull] public readonly Expression Value; - - internal Argument(Coordinate c, string name, [CanBeNull] Expression value = null) : base(c) - { - Name = name; - Value = value; - } - - /// - public override void ExecuteIn(Environment environment) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Attributes/NewAttribute.cs b/src/PatchManager.SassyPatching/Nodes/Attributes/NewAttribute.cs deleted file mode 100644 index 19c7c62..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Attributes/NewAttribute.cs +++ /dev/null @@ -1,9 +0,0 @@ -using PatchManager.SassyPatching.Nodes.Expressions; - -namespace PatchManager.SassyPatching.Nodes.Attributes; - -public class NewAttribute : SelectorAttribute -{ - public List Arguments; - public NewAttribute(Coordinate c, List arguments) : base(c) => Arguments = arguments; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireAnd.cs b/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireAnd.cs deleted file mode 100644 index 0964b0e..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireAnd.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions; - -public class RequireAnd : RequireExpression -{ - public RequireExpression LeftHandSide; - public RequireExpression RightHandSide; - - public RequireAnd(Coordinate c, RequireExpression lhs, RequireExpression rhs) : base(c) - { - LeftHandSide = lhs; - RightHandSide = rhs; - } - - public override bool Execute(IReadOnlyCollection loadedMods, Environment e) => - LeftHandSide.Execute(loadedMods, e) && RightHandSide.Execute(loadedMods, e); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireExpression.cs b/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireExpression.cs deleted file mode 100644 index 37006eb..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireExpression.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions; - -/// -/// Represents a node in a require expression -/// -public abstract class RequireExpression : Node -{ - internal RequireExpression(Coordinate c) : base(c) { } - - /// - public override void ExecuteIn(Environment environment) { } - - public abstract bool Execute(IReadOnlyCollection loadedMods, Environment e); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireGuid.cs b/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireGuid.cs deleted file mode 100644 index 14c52df..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireGuid.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions; - -public class RequireGuid : RequireExpression -{ - public string Guid; - - public RequireGuid(Coordinate c, string guid) : base(c) => Guid = guid; - - public override bool Execute(IReadOnlyCollection loadedMods, Environment e) => loadedMods.Contains(Guid.Interpolate(e)); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireNot.cs b/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireNot.cs deleted file mode 100644 index c5cef87..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireNot.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions; - -public class RequireNot : RequireExpression -{ - public RequireExpression Child; - - public RequireNot(Coordinate c, RequireExpression child) : base(c) => Child = child; - public override bool Execute(IReadOnlyCollection loadedMods, Environment e) => !Child.Execute(loadedMods, e); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireOr.cs b/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireOr.cs deleted file mode 100644 index 9c28796..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Attributes/RequireExpressions/RequireOr.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions; - -public class RequireOr : RequireExpression -{ - public RequireExpression LeftHandSide; - public RequireExpression RightHandSide; - - public RequireOr(Coordinate c, RequireExpression lhs, RequireExpression rhs) : base(c) - { - LeftHandSide = lhs; - RightHandSide = rhs; - } - - public override bool Execute(IReadOnlyCollection loadedMods, Environment e) => - LeftHandSide.Execute(loadedMods, e) || RightHandSide.Execute(loadedMods, e); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Attributes/RequireModAttribute.cs b/src/PatchManager.SassyPatching/Nodes/Attributes/RequireModAttribute.cs deleted file mode 100644 index c92c4d6..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Attributes/RequireModAttribute.cs +++ /dev/null @@ -1,12 +0,0 @@ -using PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions; - -namespace PatchManager.SassyPatching.Nodes.Attributes; -/// -/// Represents an attribute that modifies a selection block to only run if a mod is loaded -/// -public class RequireModAttribute : SelectorAttribute -{ - public readonly RequireExpression Expression; - - internal RequireModAttribute(Coordinate c, RequireExpression expression) : base(c) => Expression = expression; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Attributes/RunAtStageAttribute.cs b/src/PatchManager.SassyPatching/Nodes/Attributes/RunAtStageAttribute.cs deleted file mode 100644 index a69a87d..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Attributes/RunAtStageAttribute.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace PatchManager.SassyPatching.Nodes.Attributes; - -/// -/// Represents an attribute that defines the stage of a selection block -/// This should only be on top level blocks -/// -public class RunAtStageAttribute : SelectorAttribute -{ - /// - /// The stage that the attributed selection block will run at - /// - public readonly string Stage; - internal RunAtStageAttribute(Coordinate c, string stage) : base(c) - { - Stage = stage; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Attributes/SelectorAttribute.cs b/src/PatchManager.SassyPatching/Nodes/Attributes/SelectorAttribute.cs deleted file mode 100644 index 78826df..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Attributes/SelectorAttribute.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Attributes; - -/// -/// Represents an attribute applied to a selection block -/// -public abstract class SelectorAttribute : Node -{ - internal SelectorAttribute(Coordinate c) : base(c) - { - } - - /// - public override void ExecuteIn(Environment environment) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Block.cs b/src/PatchManager.SassyPatching/Nodes/Block.cs deleted file mode 100644 index 5a023b8..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Block.cs +++ /dev/null @@ -1,46 +0,0 @@ -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes; - -/// -/// Represents a group of nodes -/// -public class Block : Node, ISelectionAction -{ - /// - /// The children of this block node - /// - public readonly List Children; - - internal Block(Coordinate c, List children) : base(c) - { - Children = children; - } - - /// - public override void ExecuteIn(Environment environment) - { - foreach (var child in Children) - { - child.ExecuteIn(environment); - } - } - - /// - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) - { - foreach (var child in Children) - { - if (child is ISelectionAction selectionAction) - { - selectionAction.ExecuteOn(environment,selectable,modifiable); - } - else - { - child.ExecuteIn(environment); - } - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/CallArgument.cs b/src/PatchManager.SassyPatching/Nodes/CallArgument.cs deleted file mode 100644 index b341a55..0000000 --- a/src/PatchManager.SassyPatching/Nodes/CallArgument.cs +++ /dev/null @@ -1,53 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Nodes.Expressions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes; - -/// -/// Represents an argument in a function call -/// -public class CallArgument : Node -{ - /// - /// The name of the argument, if it is a named argument - /// - [CanBeNull] public readonly string ArgumentName; - /// - /// The value passed to the function/mixin being called/instantiated - /// - public readonly Expression ArgumentValue; - - /// - /// Creates a named call argument - /// - /// The location of the argument - /// The name of the argument - /// The value being passed - public CallArgument(Coordinate c, [CanBeNull] string argumentName, Expression argumentValue) : base(c) - { - ArgumentName = argumentName; - ArgumentValue = argumentValue; - } - - internal CallArgument(Coordinate c, Expression argumentValue) : base(c) - { - ArgumentName = null; - ArgumentValue = argumentValue; - } - - /// - public override void ExecuteIn(Environment environment) - { - } - - public PatchArgument Compute(Environment environment) - { - return new PatchArgument - { - ArgumentName = ArgumentName, - ArgumentDataValue = ArgumentValue.Compute(environment) - }; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/ErrorNode.cs b/src/PatchManager.SassyPatching/Nodes/ErrorNode.cs deleted file mode 100644 index fc88ffc..0000000 --- a/src/PatchManager.SassyPatching/Nodes/ErrorNode.cs +++ /dev/null @@ -1,25 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes; - -/// -/// A node representing a transformation error -/// -public class ErrorNode : Node -{ - /// - /// The error message - /// - public string Error; - internal ErrorNode(Coordinate c, string error) : base(c) - { - Error = error; - } - - /// - public override void ExecuteIn(Environment environment) - { - throw new InterpreterException(Coordinate, Error); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Add.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Add.cs deleted file mode 100644 index 702c0cc..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Add.cs +++ /dev/null @@ -1,29 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; - -/// -/// Represents a binary expression which adds its 2 children together and returns the result -/// -public class Add : Binary -{ - internal Add(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide + rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate, "add", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } - - internal override bool ShortCircuitOn(DataValue dataValue) => false; - internal override DataValue ShortCircuitDataValue => null; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/And.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/And.cs deleted file mode 100644 index c04bfcb..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/And.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; - -/// -/// Represents a binary expression that returns true if both children are truthy (short circuits) -/// -/// -public class And : Binary -{ - public And(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) => rightHandSide.Truthy; - - internal override bool ShortCircuitOn(DataValue dataValue) => !dataValue.Truthy; - - internal override DataValue ShortCircuitDataValue => false; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Binary.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Binary.cs deleted file mode 100644 index a79c9b6..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Binary.cs +++ /dev/null @@ -1,43 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; - -/// -/// Represents a binary expressions which performs a computation on 2 values to return one value -/// -public abstract class Binary : Expression -{ - /// - /// The left hand side of this expression - /// - public readonly Expression LeftHandSide; - /// - /// The right hand side of this expression - /// - public readonly Expression RightHandSide; - - internal Binary(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c) - { - LeftHandSide = leftHandSide; - RightHandSide = rightHandSide; - } - - internal abstract DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide); - - internal abstract bool ShortCircuitOn(DataValue dataValue); - - internal abstract DataValue ShortCircuitDataValue { get; } - - /// - public override DataValue Compute(Environment environment) - { - var lhs = LeftHandSide.Compute(environment); - if (ShortCircuitOn(lhs)) - { - return ShortCircuitDataValue; - } - - var rhs = RightHandSide.Compute(environment); - return GetResult(lhs, rhs); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Divide.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Divide.cs deleted file mode 100644 index e55d09d..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Divide.cs +++ /dev/null @@ -1,29 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; - -/// -/// Represents a binary expression which divides the left hand side by the right hand side -/// -public class Divide : Binary -{ - internal Divide(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide / rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate, "divide", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } - - internal override bool ShortCircuitOn(DataValue dataValue) => false; - internal override DataValue ShortCircuitDataValue => null; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/EqualTo.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/EqualTo.cs deleted file mode 100644 index b7594a5..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/EqualTo.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; - -/// -/// Represents a binary expression that returns true if both of its children are equal -/// -public class EqualTo : Binary -{ - internal EqualTo(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) => - leftHandSide == rightHandSide; - - internal override bool ShortCircuitOn(DataValue dataValue) => false; - - internal override DataValue ShortCircuitDataValue => null; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/GreaterThan.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/GreaterThan.cs deleted file mode 100644 index e5cea44..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/GreaterThan.cs +++ /dev/null @@ -1,30 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; - -/// -/// Represents a binary expression that returns true if its left hand side is greater than its right hand side -/// -public class GreaterThan : Binary -{ - internal GreaterThan(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide > rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate,"perform a relational comparison (>)", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } - - internal override bool ShortCircuitOn(DataValue dataValue) => false; - - internal override DataValue ShortCircuitDataValue => null; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/GreaterThanEqual.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/GreaterThanEqual.cs deleted file mode 100644 index de9ed83..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/GreaterThanEqual.cs +++ /dev/null @@ -1,29 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; -/// -/// Represents a binary expression that returns true if its left hand side is greater than or equal to its right hand side -/// -public class GreaterThanEqual : Binary -{ - internal GreaterThanEqual(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide >= rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate,"perform a relational comparison (>=)", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } - - internal override bool ShortCircuitOn(DataValue dataValue) => false; - - internal override DataValue ShortCircuitDataValue => null; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/LesserThan.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/LesserThan.cs deleted file mode 100644 index 5c7b9b4..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/LesserThan.cs +++ /dev/null @@ -1,30 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; -/// -/// Represents a binary expression that returns true if its left hand side is less than its right hand side -/// -public class LesserThan : Binary -{ - internal LesserThan(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - - try - { - return leftHandSide < rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate,"perform a relational comparison (<)", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } - - internal override bool ShortCircuitOn(DataValue dataValue) => false; - - internal override DataValue ShortCircuitDataValue => null; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/LesserThanEqual.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/LesserThanEqual.cs deleted file mode 100644 index 87b07d1..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/LesserThanEqual.cs +++ /dev/null @@ -1,28 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; -/// -/// Represents a binary expression that returns true if its left hand side is less than or equal to its right hand side -/// -public class LesserThanEqual : Binary -{ - internal LesserThanEqual(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide <= rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate,"perform a relational comparison (<=)", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } - - internal override bool ShortCircuitOn(DataValue dataValue) => false; - internal override DataValue ShortCircuitDataValue => null; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Multiply.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Multiply.cs deleted file mode 100644 index 154490f..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Multiply.cs +++ /dev/null @@ -1,32 +0,0 @@ -using System.Text; -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; -/// -/// Represents a binary expression which multiplies its 2 children together and returns the result -/// -public class Multiply : Binary -{ - internal Multiply(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide * rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate, "multiply", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } - - - - internal override bool ShortCircuitOn(DataValue dataValue) => false; - - internal override DataValue ShortCircuitDataValue => null; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/NotEqualTo.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/NotEqualTo.cs deleted file mode 100644 index 610cf85..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/NotEqualTo.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; -/// -/// Represents a binary expression that returns true if both of its children are not equal -/// -public class NotEqualTo : Binary -{ - internal NotEqualTo(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) => - leftHandSide != rightHandSide; - - internal override bool ShortCircuitOn(DataValue dataValue) => false; - - internal override DataValue ShortCircuitDataValue => null; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Or.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Or.cs deleted file mode 100644 index 5c43fb6..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Or.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; -/// -/// Represents a binary expression that returns true if either child is truthy (short circuits) -/// -/// -public class Or : Binary -{ - internal Or(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - // This should only be called if the left hand side is falsy - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) => rightHandSide.Truthy; - - internal override bool ShortCircuitOn(DataValue dataValue) => dataValue.Truthy; - - internal override DataValue ShortCircuitDataValue => true; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Remainder.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Remainder.cs deleted file mode 100644 index 5637c66..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Remainder.cs +++ /dev/null @@ -1,29 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; -/// -/// Represents a binary expression which divides the left hand side by the right hand side and returns the remainder -/// -public class Remainder : Binary -{ - internal Remainder(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide % rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate, "take the remainder of", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } - - internal override bool ShortCircuitOn(DataValue dataValue) => false; - - internal override DataValue ShortCircuitDataValue => null; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Subscript.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Subscript.cs deleted file mode 100644 index c484611..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Subscript.cs +++ /dev/null @@ -1,39 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; - -/// -/// A binary expression which indexes the left hand side by the right hand side and returns the result -/// -public class Subscript : Binary -{ - internal Subscript(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - // ReSharper disable once CognitiveComplexity - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide[rightHandSide]; - } - catch (IndexOutOfRangeException indexOutOfRangeException) - { - throw new ListIndexOutOfRangeException(Coordinate, indexOutOfRangeException.Message); - } - catch (KeyNotFoundException keyNotFoundException) - { - throw new DictionaryKeyNotFoundException(Coordinate, keyNotFoundException.Message); - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate, "subscript", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } - - internal override bool ShortCircuitOn(DataValue dataValue) => false; - - internal override DataValue ShortCircuitDataValue => null; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Subtract.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Subtract.cs deleted file mode 100644 index 54205be..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Binary/Subtract.cs +++ /dev/null @@ -1,29 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Binary; -/// -/// Represents a binary expression which subtracts the right hand side from the left hand side -/// -public class Subtract : Binary -{ - internal Subtract(Coordinate c, Expression leftHandSide, Expression rightHandSide) : base(c, leftHandSide, rightHandSide) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide - rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate, "subtract", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } - - internal override bool ShortCircuitOn(DataValue dataValue) => false; - - internal override DataValue ShortCircuitDataValue => null; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Closure.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Closure.cs deleted file mode 100644 index fb92d1b..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Closure.cs +++ /dev/null @@ -1,30 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions; - -/// -/// Represents a function definition -/// -public class Closure : Expression -{ - /// - /// The list of arguments the function takes - /// - public readonly List Arguments; - /// - /// The list of statements to be executed upon a function call - /// - public readonly List Body; - internal Closure(Coordinate c, List arguments, List body) : base(c) - { - Arguments = arguments; - Body = body; - } - - /// - public override DataValue Compute(Environment environment) - { - return new SassyPatchClosure(environment.Snapshot(), this); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Expression.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Expression.cs deleted file mode 100644 index dd97cc3..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Expression.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions; - -/// -/// Represents an expression node -/// -public abstract class Expression : Node -{ - - /// - /// Computes the value of the expression in the given environment - /// - /// The environment to compute the expression within - /// The computed value - /// Thrown if any error happens - public abstract DataValue Compute(Environment environment); - internal Expression(Coordinate c) : base(c) - { - } - - /// - public override void ExecuteIn(Environment environment) - { - _ = Compute(environment); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/ListNode.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/ListNode.cs deleted file mode 100644 index 1e0fbbb..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/ListNode.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions; - -/// -/// Represents a list initializer -/// -public class ListNode : Expression -{ - /// - /// The list of values contained within this list - /// - public readonly List Expressions; - internal ListNode(Coordinate c, List expressions) : base(c) - { - Expressions = expressions; - } - - /// - public override DataValue Compute(Environment environment) - { - return Expressions.Select(x => x.Compute(environment)).ToList(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/LocalVariableReference.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/LocalVariableReference.cs deleted file mode 100644 index 5db6981..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/LocalVariableReference.cs +++ /dev/null @@ -1,25 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions; - -/// -/// Represents a local variable (indexing into $current) -/// -public class LocalVariableReference : Expression -{ - /// - /// The local variable $current[...] - /// - public readonly string LocalVariableName; - internal LocalVariableReference(Coordinate c, string localVariableName) : base(c) - { - LocalVariableName = localVariableName; - } - - /// - public override DataValue Compute(Environment environment) - { - var current = environment["current"].Dictionary; - return current.TryGetValue(LocalVariableName, out var compute) ? compute : new DataValue(DataValue.DataType.None); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/MemberCall.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/MemberCall.cs deleted file mode 100644 index d59dbd9..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/MemberCall.cs +++ /dev/null @@ -1,79 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Execution; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions; - -/// -/// Represents a member call, or a call syntax where the left hand side is the first argument -/// -public class MemberCall : Expression -{ - /// - /// The object getting member called - /// - public readonly Expression LeftHandSide; - /// - /// The function being called, first tries to find a function named [LeftHandSide Type].name then name - /// - public readonly string FunctionName; - /// - /// The arguments being passed to the function, other than the left hand side - /// - public readonly List Arguments; - - internal MemberCall(Coordinate c, Expression leftHandSide, string functionName, List arguments) : base(c) - { - LeftHandSide = leftHandSide; - FunctionName = functionName; - Arguments = arguments; - } - - /// - public override DataValue Compute(Environment environment) - { - var lhs = LeftHandSide.Compute(environment); - var lhsType = lhs.Type.ToString().ToLowerInvariant(); - var args = new List - { - new PatchArgument - { - ArgumentName = null, - ArgumentDataValue = lhs - } - }; - args.AddRange(Arguments.Select(x => x.Compute(environment))); - if (environment.GlobalEnvironment.AllFunctions.TryGetValue($"{lhsType}.{FunctionName}", out var overloadedFunction)) - { - try - { - return overloadedFunction.Execute(environment,args); - } - catch (InterpreterException i) - { - throw; - } - catch (Exception e) - { - throw new InterpreterException(Coordinate, e.ToString()); - } - } - if (environment.GlobalEnvironment.AllFunctions.TryGetValue(FunctionName, out var function)) - { - try - { - return function.Execute(environment,args); - } - catch (InterpreterException i) - { - throw; - } - catch (Exception e) - { - throw new InterpreterException(Coordinate, e.ToString()); - } - } - - throw new InterpreterException(Coordinate, $"Attempting to call {FunctionName}/{lhsType}.{FunctionName} which does not exist"); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/ObjectNode.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/ObjectNode.cs deleted file mode 100644 index f173ba4..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/ObjectNode.cs +++ /dev/null @@ -1,24 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions; - -/// -/// Represents an object initializer -/// -public class ObjectNode : Expression -{ - /// - /// The fields being initialized in this object - /// - public readonly List Initializers; - internal ObjectNode(Coordinate c, List initializers) : base(c) - { - Initializers = initializers; - } - - /// - public override DataValue Compute(Environment environment) - { - return Initializers.ToDictionary(x => x.Key, x => x.Value.Compute(environment)); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/SimpleCall.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/SimpleCall.cs deleted file mode 100644 index 87dd878..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/SimpleCall.cs +++ /dev/null @@ -1,47 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions; - -/// -/// Represents a simple function call -/// -public class SimpleCall : Expression -{ - /// - /// The function being called - /// - public readonly string FunctionName; - /// - /// The arguments being passed to the function call - /// - public readonly List Arguments; - - internal SimpleCall(Coordinate c, string functionName, List arguments) : base(c) - { - FunctionName = functionName; - Arguments = arguments; - } - - /// - public override DataValue Compute(Environment environment) - { - if (environment.GlobalEnvironment.AllFunctions.TryGetValue(FunctionName, out var function)) - { - try - { - return function.Execute(environment, Arguments.Select(x => x.Compute(environment)).ToList()); - } - catch (InterpreterException i) - { - throw; - } - catch (Exception e) - { - throw new InterpreterException(Coordinate, e.ToString()); - } - } - - throw new InterpreterException(Coordinate, $"Attempting to call {FunctionName} which does not exist"); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Ternary.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Ternary.cs deleted file mode 100644 index c0ebd54..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Ternary.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions; - -/// -/// Represents a ternary expression, which computes the left hand side if the condition is true otherwise the righthand side -/// -public class Ternary : Expression -{ - /// - /// The expression to be computed if the condition is true - /// - public readonly Expression LeftHandSide; - /// - /// The condition to be tested - /// - public readonly Expression Condition; - /// - /// The expression to be computed if the condition is false - /// - public readonly Expression RightHandSide; - - internal Ternary(Coordinate c, Expression leftHandSide, Expression condition, Expression rightHandSide) : base(c) - { - LeftHandSide = leftHandSide; - Condition = condition; - RightHandSide = rightHandSide; - } - - /// - public override DataValue Compute(Environment environment) => Condition.Compute(environment).Truthy - ? LeftHandSide.Compute(environment) - : RightHandSide.Compute(environment); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Implicit.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Implicit.cs deleted file mode 100644 index 949abfa..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Implicit.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Unary; - -/// -/// -/// Represents an implicit operation node, which is a node that grabs the variable $value from the environment and applies a computation to it -/// -/// -/// $value is always the value of the variable/field being modified -/// -/// -public abstract class Implicit : Unary -{ - internal Implicit(Coordinate c, Expression child) : base(c, child) - { - } - internal abstract DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide); - - internal override DataValue GetResult(DataValue child) - { - throw new Exception("Unreachable"); - } - - /// - public override DataValue Compute(Environment environment) => GetResult(environment["value"], Child.Compute(environment)); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitAdd.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitAdd.cs deleted file mode 100644 index f6d2060..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitAdd.cs +++ /dev/null @@ -1,32 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Unary; - -/// -/// Represents an implicit addition, which adds the child to $value -/// -public class ImplicitAdd : Implicit -{ - internal ImplicitAdd(Coordinate c, Expression child) : base(c, child) - { - } - - // There should be a value called "$value" in the current environment, a literal new environment gets made here w/ that value set - internal override DataValue GetResult(DataValue child) => throw - // Should be unreachable - new Exception("Unreachable"); - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide + rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate, "add", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } - -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitDivide.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitDivide.cs deleted file mode 100644 index c4b01a0..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitDivide.cs +++ /dev/null @@ -1,26 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Unary; - -/// -/// Represent an implicit division which divides $value by its child -/// -public class ImplicitDivide : Implicit -{ - internal ImplicitDivide(Coordinate c, Expression child) : base(c, child) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide / rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate, "divide", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitMultiply.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitMultiply.cs deleted file mode 100644 index 7145c10..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitMultiply.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System.Text; -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Unary; - -/// -/// Represents an implicit multiplication which multiplies $value by its child -/// -public class ImplicitMultiply : Implicit -{ - internal ImplicitMultiply(Coordinate c, Expression child) : base(c, child) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide * rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate, "multiply", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitSubtract.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitSubtract.cs deleted file mode 100644 index 591227b..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/ImplicitSubtract.cs +++ /dev/null @@ -1,26 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Unary; - -/// -/// Represents an implicit subtraction which subtracts its child from $value -/// -public class ImplicitSubtract : Implicit -{ - internal ImplicitSubtract(Coordinate c, Expression child) : base(c, child) - { - } - - internal override DataValue GetResult(DataValue leftHandSide, DataValue rightHandSide) - { - try - { - return leftHandSide - rightHandSide; - } - catch (DataValueOperationException) - { - throw new BinaryExpressionTypeException(Coordinate, "subtract", leftHandSide.Type.ToString(), - rightHandSide.Type.ToString()); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Negate.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Negate.cs deleted file mode 100644 index 8204947..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Negate.cs +++ /dev/null @@ -1,25 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Unary; - -/// -/// Represents a negation operation which returns the negative value of its child -/// -public class Negate : Unary -{ - internal Negate(Coordinate c, Expression child) : base(c, child) - { - } - - internal override DataValue GetResult(DataValue child) - { - try - { - return -child; - } - catch (DataValueOperationException) - { - throw new UnaryTypeException(Coordinate, "negate", child.Type.ToString()); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Not.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Not.cs deleted file mode 100644 index c80cc2e..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Not.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace PatchManager.SassyPatching.Nodes.Expressions.Unary; - -/// -/// Represents a not operation which returns the opposite of the truthiness of its child -/// -/// -public class Not : Unary -{ - internal Not(Coordinate c, Expression child) : base(c, child) - { - } - - internal override DataValue GetResult(DataValue child) => !child; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Positive.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Positive.cs deleted file mode 100644 index d1fd150..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Positive.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace PatchManager.SassyPatching.Nodes.Expressions.Unary; - -/// -/// Represents a positive expression which returns its child -/// -public class Positive : Unary -{ - internal Positive(Coordinate c, Expression child) : base(c, child) - { - } - - internal override DataValue GetResult(DataValue child) => +child; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Unary.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Unary.cs deleted file mode 100644 index a96ef2d..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/Unary/Unary.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions.Unary; - -/// -/// Represents a unary expression (an expression with one child) -/// -public abstract class Unary : Expression -{ - /// - /// The child of this expression - /// - public readonly Expression Child; - - - - internal Unary(Coordinate c, Expression child) : base(c) - { - Child = child; - } - - internal abstract DataValue GetResult(DataValue child); - - /// - public override DataValue Compute(Environment environment) - { - return GetResult(Child.Compute(environment)); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/ValueNode.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/ValueNode.cs deleted file mode 100644 index 7ae7b63..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/ValueNode.cs +++ /dev/null @@ -1,37 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions; - -/// -/// Represents a literal value -/// -public class ValueNode : Expression -{ - /// - /// The literal value - /// - public readonly DataValue StoredDataValue; - internal ValueNode(Coordinate c, DataValue storedDataValue) : base(c) - { - StoredDataValue = storedDataValue; - } - - /// - public override DataValue Compute(Environment environment) - { - if (!StoredDataValue.IsString) - { - return StoredDataValue; - } - - try - { - return StoredDataValue.String.Interpolate(environment); - } - catch (Exception e) - { - throw new InterpolationException(Coordinate, e.Message); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Expressions/VariableReference.cs b/src/PatchManager.SassyPatching/Nodes/Expressions/VariableReference.cs deleted file mode 100644 index 6774fda..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Expressions/VariableReference.cs +++ /dev/null @@ -1,33 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Expressions; - -/// -/// Represents a reference to a variable within the current environment -/// -public class VariableReference : Expression -{ - /// - /// The variable being referenced - /// - public readonly string VariableName; - internal VariableReference(Coordinate c, string variableName) : base(c) - { - VariableName = variableName; - } - - /// - public override DataValue Compute(Environment environment) - { - try - { - return environment[VariableName]; - } - catch (KeyNotFoundException keyNotFoundException) - { - throw new InvalidVariableReferenceException(Coordinate, - $"${VariableName} does not exist in the current scope"); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Indexers/EverythingIndexer.cs b/src/PatchManager.SassyPatching/Nodes/Indexers/EverythingIndexer.cs deleted file mode 100644 index 288a2c5..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Indexers/EverythingIndexer.cs +++ /dev/null @@ -1,3 +0,0 @@ -namespace PatchManager.SassyPatching.Nodes.Indexers; - -public class EverythingIndexer(Coordinate c) : Indexer(c); \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Indexers/Indexer.cs b/src/PatchManager.SassyPatching/Nodes/Indexers/Indexer.cs deleted file mode 100644 index b11b9b3..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Indexers/Indexer.cs +++ /dev/null @@ -1,18 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Indexers; - -/// -/// Represents a field indexer -/// -public abstract class Indexer : Node -{ - internal Indexer(Coordinate c) : base(c) - { - } - - /// - public override void ExecuteIn(Environment environment) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Indexers/SingleIndexer.cs b/src/PatchManager.SassyPatching/Nodes/Indexers/SingleIndexer.cs deleted file mode 100644 index cd36f56..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Indexers/SingleIndexer.cs +++ /dev/null @@ -1,8 +0,0 @@ -using PatchManager.SassyPatching.Nodes.Expressions; - -namespace PatchManager.SassyPatching.Nodes.Indexers; - -public class SingleIndexer(Coordinate c, Expression index) : Indexer(c) -{ - public Expression Index => index; -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/KeyValueNode.cs b/src/PatchManager.SassyPatching/Nodes/KeyValueNode.cs deleted file mode 100644 index 71b6cff..0000000 --- a/src/PatchManager.SassyPatching/Nodes/KeyValueNode.cs +++ /dev/null @@ -1,30 +0,0 @@ -using PatchManager.SassyPatching.Nodes.Expressions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes; - -/// -/// A node representing a Key/Value pair in an Objects definition -/// -public class KeyValueNode : Node -{ - /// - /// They field to be defined - /// - public readonly string Key; - /// - /// A node representing the value of the field - /// - public readonly Expression Value; - - internal KeyValueNode(Coordinate c, string key, Expression value) : base(c) - { - Key = key; - Value = value; - } - - /// - public override void ExecuteIn(Environment environment) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Node.cs b/src/PatchManager.SassyPatching/Nodes/Node.cs deleted file mode 100644 index 9bcf9b3..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Node.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes; - -/// -/// An abstract class representing a node in the tree of a patch file -/// -public abstract class Node -{ - /// - /// The location of this node - /// - public readonly Coordinate Coordinate; - - /// - /// Creates a new node at a location - /// - /// The location of the node - internal Node(Coordinate c) - { - Coordinate = c; - } - - /// - /// Execute this node in the given environment - /// - /// The given environment - public abstract void ExecuteIn(Environment environment); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/SassyPatch.cs b/src/PatchManager.SassyPatching/Nodes/SassyPatch.cs deleted file mode 100644 index ee3b043..0000000 --- a/src/PatchManager.SassyPatching/Nodes/SassyPatch.cs +++ /dev/null @@ -1,28 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes; - -/// -/// The top level node of a patch file, represents the entire file -/// -public class SassyPatch : Node -{ - /// - /// The list of statements in this patch - /// - public readonly List Children; - - internal SassyPatch(Coordinate c, List children) : base(c) - { - Children = children; - } - - /// - public override void ExecuteIn(Environment environment) - { - foreach (var child in Children) - { - child.ExecuteIn(environment); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/ChildSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/ChildSelector.cs deleted file mode 100644 index 59c1451..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/ChildSelector.cs +++ /dev/null @@ -1,54 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -/// -/// Represents a selector that selects children of a selectable that match a selector -/// -public class ChildSelector : Selector -{ - /// - /// The selector to get the parent selectables - /// - public readonly Selector Parent; - /// - /// The selector to match children with - /// - public readonly Selector Child; - internal ChildSelector(Coordinate c, Selector parent, Selector child) : base(c) - { - Parent = parent; - Child = child; - } - - /// - public override List SelectAll(List selectables) => - SelectChildren(Parent.SelectAll(selectables)); - - private List SelectChildren(List selectedParents) - { - - List result = new(); - // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator - foreach (var selectable in selectedParents) - { - // We are going to get every child of this selectable - var allChildren = Child.SelectAll(selectable.Selectable.SelectEverything().Select(x => new SelectableWithEnvironment - { - Selectable = x, - Environment = new Environment(selectable.Environment.GlobalEnvironment, selectable.Environment) - }).ToList()); - result = SelectionUtilities.CombineSelections(result, allChildren); - } - return result; - } - - /// - public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) => - SelectChildren(Parent.SelectAllTopLevel(type, name, data, baseEnvironment, out rulesetMatchingObject)); - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) => - SelectChildren(Parent.CreateNew(rulesetArguments, baseEnvironment, out newAsset)); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/ClassCaptureSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/ClassCaptureSelector.cs deleted file mode 100644 index 57f59e0..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/ClassCaptureSelector.cs +++ /dev/null @@ -1,60 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -public class ClassCaptureSelector : Selector -{ - public readonly string ClassName; - public List Captures; - internal ClassCaptureSelector(Coordinate c, string className, List captures) : base(c) - { - ClassName = className; - Captures = captures; - } - - /// - public override List SelectAll(List selectableWithEnvironments) - { - List newList = new(); - foreach (var selectableWithEnvironment in selectableWithEnvironments) - { - var interpolated = ""; - try - { - interpolated = ClassName.Interpolate(selectableWithEnvironment.Environment); - } - catch (Exception e) - { - throw new InterpolationException(Coordinate, e.Message); - } - - if (selectableWithEnvironment.Selectable.MatchesClass(interpolated,out var value)) - { - selectableWithEnvironment.Environment["current"] = value; - foreach (var node in Captures) - { - node.ExecuteIn(selectableWithEnvironment.Environment); - } - selectableWithEnvironment.Environment.ScopedValues.Remove("current"); - newList.Add(selectableWithEnvironment); - } - } - return newList; - } - - /// - public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) - { - rulesetMatchingObject = null; - return new(); - } - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) - { - newAsset = null; - return new(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/ClassSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/ClassSelector.cs deleted file mode 100644 index 53136fc..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/ClassSelector.cs +++ /dev/null @@ -1,39 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -/// -/// Represents a selector that selects selectables that have a class -/// -public class ClassSelector : Selector -{ - /// - /// The class to select against - /// - public readonly string ClassName; - internal ClassSelector(Coordinate c, string className) : base(c) - { - ClassName = className; - } - - /// - public override List SelectAll(List selectableWithEnvironments) - { - return selectableWithEnvironments.Where(selectable => selectable.Selectable.MatchesClass(ClassName.Interpolate(selectable.Environment))).ToList(); - } - - /// - public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) - { - rulesetMatchingObject = null; - return new(); - } - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) - { - newAsset = null; - return new(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/CombinationSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/CombinationSelector.cs deleted file mode 100644 index 402c3e5..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/CombinationSelector.cs +++ /dev/null @@ -1,81 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; -/// -/// Represents a selector that selects all selectables that get selected by any of the selectors contained within -/// -public class CombinationSelector : Selector -{ - /// - /// The list of selectors to get the combination selection of - /// - public readonly List Selectors; - internal CombinationSelector(Coordinate c, Selector lhs, Selector rhs) : base(c) - { - Selectors = new(); - if (lhs is CombinationSelector lcs) - { - Selectors.AddRange(lcs.Selectors); - } - else - { - Selectors.Add(lhs); - } - - if (rhs is CombinationSelector rcs) - { - Selectors.AddRange(rcs.Selectors); - } - else - { - Selectors.Add(rhs); - } - } - - /// - public override List SelectAll(List selectableWithEnvironments) - { - var result = new List(); - // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator - foreach (var selector in Selectors) - { - result = SelectionUtilities.CombineSelections(result, selector.SelectAll(selectableWithEnvironments)); - } - return result; - } - - /// - public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) - { - var start = new List(); - rulesetMatchingObject = null; - foreach (var selector in Selectors) - { - // ReSharper disable once IdentifierTypo - start = SelectionUtilities.CombineSelections(start,selector.SelectAllTopLevel(type, name, data,baseEnvironment, out var rsmo)); - if (rsmo != null && rulesetMatchingObject == null) - { - rulesetMatchingObject = rsmo; - } - } - return start; - } - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) - { - var start = new List(); - newAsset = null; - foreach (var selector in Selectors) - { - start = SelectionUtilities.CombineSelections(start, selector.CreateNew(rulesetArguments,baseEnvironment, out var na)); - if (na != null && newAsset == null) - { - newAsset = na; - } - } - - return start; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/ElementAdditionSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/ElementAdditionSelector.cs deleted file mode 100644 index 1f66412..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/ElementAdditionSelector.cs +++ /dev/null @@ -1,68 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -/// -/// Represents a selector that adds an element to a selectable and selects it -/// -public class ElementAdditionSelector : Selector -{ - /// - /// The element type to add to the selectable - /// - public string ElementName; - internal ElementAdditionSelector(Coordinate c, string elementName) : base(c) - { - ElementName = elementName; - } - - /// - public override List SelectAll(List selectableWithEnvironments) - { - try - { - List result = new(); - foreach (var selectable in selectableWithEnvironments) - { - var interpolated = ""; - try - { - interpolated = ElementName.Interpolate(selectable.Environment); - } - catch (Exception e) - { - throw new InterpolationException(Coordinate, e.Message); - } - var addedElement = selectable.Selectable.AddElement(interpolated); - result.Add(new SelectableWithEnvironment - { - Selectable = addedElement, - Environment = new Environment(selectable.Environment.GlobalEnvironment,selectable.Environment) - }); - } - - return result; - } - catch (Exception e) - { - throw new InterpreterException(Coordinate, e.ToString()); - } - } - - /// - public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) - { - rulesetMatchingObject = null; - return new(); - } - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) - { - newAsset = null; - return new(); - - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/ElementSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/ElementSelector.cs deleted file mode 100644 index 8d6c308..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/ElementSelector.cs +++ /dev/null @@ -1,54 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -/// -/// Represents a selector that selects all selectables that are an element type -/// -public class ElementSelector : Selector -{ - /// - /// The element type to select - /// - public readonly string ElementName; - internal ElementSelector(Coordinate c, string elementName) : base(c) - { - ElementName = elementName; - } - - /// - public override List SelectAll(List selectableWithEnvironments) - { - return selectableWithEnvironments.Where(selectable => - { - var interpolated = ""; - try - { - interpolated = ElementName.Interpolate(selectable.Environment); - } - catch (Exception e) - { - throw new InterpolationException(Coordinate, e.Message); - } - - var result = selectable.Selectable.MatchesElement(interpolated); - return result; - }).ToList(); - } - - /// - public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) - { - rulesetMatchingObject = null; - return new(); - } - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) - { - newAsset = null; - return new(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/EnsureSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/EnsureSelector.cs deleted file mode 100644 index 1cf3161..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/EnsureSelector.cs +++ /dev/null @@ -1,84 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -/// -/// Represents a selector that adds an element to a selectable and selects it -/// -public class EnsureSelector : Selector -{ - /// - /// The element type to add to the selectable - /// - public string ElementName; - internal EnsureSelector(Coordinate c, string elementName) : base(c) - { - ElementName = elementName; - } - - /// - public override List SelectAll(List selectableWithEnvironments) - { - try - { - var baseList = selectableWithEnvironments.Where(selectable => - { - var interpolated = ""; - try - { - interpolated = ElementName.Interpolate(selectable.Environment); - } - catch (Exception e) - { - throw new InterpolationException(Coordinate, e.Message); - } - var result = selectable.Selectable.MatchesElement(interpolated); - return result; - }).ToList(); - // return baseList.Count == 0 ? selectables.Select(selectable => selectable.AddElement(ElementName)).ToList() : baseList; - if (baseList.Count == 0) - { - foreach (var selectable in selectableWithEnvironments) - { - var interpolated = ""; - try - { - interpolated = ElementName.Interpolate(selectable.Environment); - } - catch (Exception e) - { - throw new InterpolationException(Coordinate, e.Message); - } - var addedElement = selectable.Selectable.AddElement(interpolated); - baseList.Add(new SelectableWithEnvironment - { - Selectable = addedElement, - Environment = new Environment(selectable.Environment.GlobalEnvironment,selectable.Environment) - }); - } - } - return baseList; - } - catch (Exception e) - { - throw new InterpreterException(Coordinate, e.ToString()); - } - } - - /// - public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) - { - rulesetMatchingObject = null; - return new(); - } - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) - { - newAsset = null; - return new(); - - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/IntersectionSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/IntersectionSelector.cs deleted file mode 100644 index 945e91b..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/IntersectionSelector.cs +++ /dev/null @@ -1,70 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -/// -/// Represents a selector that selects all selectables that get selected by all of the selectors contained within -/// -public class IntersectionSelector : Selector -{ - /// - /// The list of selectors to get the intersection selection of - /// - public readonly List Selectors; - internal IntersectionSelector(Coordinate c, Selector lhs, Selector rhs) : base(c) - { - Selectors = new(); - if (lhs is IntersectionSelector lis) - { - Selectors.AddRange(lis.Selectors); - } - else - { - Selectors.Add(lhs); - } - - if (rhs is IntersectionSelector ris) - { - Selectors.AddRange(ris.Selectors); - } - else - { - Selectors.Add(rhs); - } - } - - /// - public override List SelectAll(List selectableWithEnvironments) - { - // ReSharper disable once ForeachCanBeConvertedToQueryUsingAnotherGetEnumerator - foreach (var selector in Selectors) - { - selectableWithEnvironments = SelectionUtilities.IntersectSelections(selectableWithEnvironments, selector.SelectAll(selectableWithEnvironments)); - } - return selectableWithEnvironments; - } - - private List SelectAllSkippingFirst(List selectables) - { - for (var i = 1; i < Selectors.Count; i++) - { - selectables = SelectionUtilities.IntersectSelections(selectables, Selectors[i].SelectAll(selectables)); - } - return selectables; - } - - /// - public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) - { - var start = Selectors[0].SelectAllTopLevel(type, name, data, baseEnvironment, out rulesetMatchingObject); - return SelectAllSkippingFirst(start); - } - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) - { - var start = Selectors[0].CreateNew(rulesetArguments,baseEnvironment, out newAsset); - return SelectAllSkippingFirst(start); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/NameSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/NameSelector.cs deleted file mode 100644 index b766bf1..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/NameSelector.cs +++ /dev/null @@ -1,39 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -/// -/// Represents a selector that matches selectables that have a name that matches a name pattern -/// -public class NameSelector : Selector -{ - /// - /// The name pattern to match against, can contain */? wildcards - /// - public readonly string NamePattern; - internal NameSelector(Coordinate c, string namePattern) : base(c) - { - NamePattern = namePattern; - } - - /// - public override List SelectAll(List selectableWithEnvironments) - { - return selectableWithEnvironments.Where(selectable => selectable.Selectable.MatchesName(NamePattern.Interpolate(selectable.Environment))).ToList(); - } - - /// - public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) - { - rulesetMatchingObject = null; - return new(); - } - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) - { - newAsset = null; - return new(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/RulesetSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/RulesetSelector.cs deleted file mode 100644 index d7608f3..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/RulesetSelector.cs +++ /dev/null @@ -1,75 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -/// -/// Represents a selector that defines the ruleset that following selectors follow -/// -public class RulesetSelector : Selector -{ - /// - /// The name of the ruleset - /// - public readonly string RulesetName; - internal RulesetSelector(Coordinate c, string rulesetName) : base(c) - { - RulesetName = rulesetName; - } - - /// - public override List SelectAll(List selectableWithEnvironments) - { - return new(); - } - - /// - public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) - { - if (!Universe.RuleSets.TryGetValue(RulesetName, out var ruleSet)) - { - throw new InterpreterException(Coordinate, $"Ruleset: {RulesetName} does not exist!"); - } - - if (ruleSet.Matches(type)) - { - rulesetMatchingObject = ruleSet.ConvertToSelectable(type, name,data); - if (rulesetMatchingObject != null) - { - return - [ - new SelectableWithEnvironment - { - Selectable = rulesetMatchingObject, - Environment = new Environment(baseEnvironment.GlobalEnvironment, baseEnvironment) - } - ]; - } - } - rulesetMatchingObject = null; - return []; - - } - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) - { - if (!Universe.RuleSets.TryGetValue(RulesetName, out var ruleSet)) - { - throw new InterpreterException(Coordinate, $"Ruleset: {RulesetName} does not exist!"); - } - - var newObject = ruleSet.CreateNew(rulesetArguments); - newAsset = newObject; - return - [ - new SelectableWithEnvironment - { - Selectable = newAsset.Selectable, - Environment = new Environment(baseEnvironment.GlobalEnvironment, baseEnvironment) - } - ]; - - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/Selector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/Selector.cs deleted file mode 100644 index 9447d32..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/Selector.cs +++ /dev/null @@ -1,48 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -/// -/// Represents a selector node -/// -public abstract class Selector : Node -{ - internal Selector(Coordinate c) : base(c) - { - } - - /// - /// Select all that match this selector from the list of selectables - /// - /// All the selectables to match - /// A list of selections - public abstract List SelectAll(List selectables); - - /// - /// Select all that match this selector from the type and data - /// - /// The type, e.g. parts_data - /// The name of the data - /// The data, a textual representation of the data - /// The base environment to create the selectables in - /// The found object that matches the ruleset - /// A list of all selections from the data - public abstract List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject); - - - /// - /// Create a new asset (flows up until the ruleset statement) - /// - /// The arguments to the ruleset - /// The reference to the newly created asset - /// The base environment to create the selectables in - /// The new assets selectables - public abstract List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset); - - /// - public override void ExecuteIn(Environment environment) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/WildcardSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/WildcardSelector.cs deleted file mode 100644 index ab2b881..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/WildcardSelector.cs +++ /dev/null @@ -1,34 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -/// -/// Represents a selection action that matches all selectables -/// -public class WildcardSelector : Selector -{ - internal WildcardSelector(Coordinate c) : base(c) - { - } - - /// - public override List SelectAll(List selectableWithEnvironments) - { - return selectableWithEnvironments; - } - - /// - public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) - { - rulesetMatchingObject = null; - return new(); - } - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) - { - newAsset = null; - return new(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/WithoutClassSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/WithoutClassSelector.cs deleted file mode 100644 index 7c9a26f..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/WithoutClassSelector.cs +++ /dev/null @@ -1,39 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -/// -/// Represents a selector that matches selectables that don't have the class defined in this -/// -public class WithoutClassSelector : Selector -{ - /// - /// The class to match against - /// - public readonly string ClassName; - internal WithoutClassSelector(Coordinate c, string className) : base(c) - { - ClassName = className; - } - - /// - public override List SelectAll(List selectableWithEnvironments) - { - return selectableWithEnvironments.Where(selectable => !selectable.Selectable.MatchesClass(ClassName.Interpolate(selectable.Environment))).ToList(); - } - - /// - public override List SelectAllTopLevel(string type,string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) - { - rulesetMatchingObject = null; - return new(); - } - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) - { - newAsset = null; - return new(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Selectors/WithoutNameSelector.cs b/src/PatchManager.SassyPatching/Nodes/Selectors/WithoutNameSelector.cs deleted file mode 100644 index 712f274..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Selectors/WithoutNameSelector.cs +++ /dev/null @@ -1,39 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Selectors; - -/// -/// Represents a selector that matches selectables that don't have a name that matches a name pattern -/// -public class WithoutNameSelector : Selector -{ - /// - /// The name pattern to match against, can contain */? wildcards - /// - public readonly string NamePattern; - internal WithoutNameSelector(Coordinate c, string namePattern) : base(c) - { - NamePattern = namePattern; - } - - /// - public override List SelectAll(List selectableWithEnvironments) - { - return selectableWithEnvironments.Where(selectable => !selectable.Selectable.MatchesName(NamePattern.Interpolate(selectable.Environment))).ToList(); - } - - /// - public override List SelectAllTopLevel(string type, string name, string data, Environment baseEnvironment, out ISelectable rulesetMatchingObject) - { - rulesetMatchingObject = null; - return new(); - } - - public override List CreateNew(List rulesetArguments, Environment baseEnvironment, out INewAsset newAsset) - { - newAsset = null; - return new(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/Conditional.cs b/src/PatchManager.SassyPatching/Nodes/Statements/Conditional.cs deleted file mode 100644 index ad2462b..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/Conditional.cs +++ /dev/null @@ -1,79 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Nodes.Expressions; -using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements; - -/// -/// Represents a conditional (if-else) statement -/// -public class Conditional : Node, ISelectionAction -{ - /// - /// The condition that is being tested - /// - public readonly Expression Condition; - /// - /// The list of nodes to be executed upon a truthy result - /// - public readonly List Body; - /// - /// The node to be executed upon a falsy result, may not exist - /// - [CanBeNull] public readonly Node Else; - - internal Conditional(Coordinate c, Expression condition, List body, [CanBeNull] Node @else = null) : base(c) - { - Condition = condition; - Body = body; - Else = @else; - } - - /// - public override void ExecuteIn(Environment environment) - { - if (Condition.Compute(environment).Truthy) - { - foreach (var child in Body) - { - child.ExecuteIn(environment); - } - } - else - { - Else?.ExecuteIn(environment); - } - } - - /// - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) - { - if (Condition.Compute(environment).Truthy) - { - foreach (var child in Body) - { - if (child is ISelectionAction selectionAction) - { - selectionAction.ExecuteOn(environment, selectable, modifiable); - } - else - { - child.ExecuteIn(environment); - } - } - } - else - { - if (Else is ISelectionAction selectionAction) - { - selectionAction.ExecuteOn(environment, selectable, modifiable); - } - else - { - Else?.ExecuteIn(environment); - } - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/Each.cs b/src/PatchManager.SassyPatching/Nodes/Statements/Each.cs deleted file mode 100644 index e44bd50..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/Each.cs +++ /dev/null @@ -1,222 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Nodes.Expressions; -using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements; - -/// -/// Represents a loop that iterates over a list/dictionary/string -/// -public class Each : Node, ISelectionAction -{ - /// - /// The variable to store the keys of iterations of this list node (optional) - /// - [CanBeNull] public readonly string KeyName; - /// - /// Where to store the values of the iterations of this list node - /// - public readonly string ValueName; - /// - /// The expression that returns what is being iterated over - /// - public readonly Expression Iterator; - public readonly List Children; - - internal Each(Coordinate c, [CanBeNull] string keyName, string valueName, Expression iterator, List children) : base(c) - { - Iterator = iterator; - Children = children; - ValueName = valueName; - KeyName = keyName; - } - - /// - public override void ExecuteIn(Environment environment) - { - var value = Iterator.Compute(environment); - if (value.IsList) - { - EachList(environment, value); - return; - } - - if (value.IsString) - { - EachString(environment, value); - return; - } - - if (value.IsDictionary) - { - EachDictionary(environment, value); - return; - } - - throw new InterpreterException(Coordinate, - $"cannot iterate over a value of type {value.Type.ToString().ToLowerInvariant()}"); - } - - private void EachDictionary(Environment environment, DataValue value) - { - foreach (var (k, v) in value.Dictionary) - { - if (KeyName != null) - { - environment[KeyName] = k; - } - - environment[ValueName] = v; - ExecuteChildren(environment); - } - } - - private void EachString(Environment environment, DataValue value) - { - if (KeyName != null) - { - for (var i = 0; i < value.String.Length; i++) - { - environment[KeyName] = i; - environment[ValueName] = value.String[i]; - ExecuteChildren(environment); - } - } - else - { - foreach (var v in value.String) - { - environment[ValueName] = v; - ExecuteChildren(environment); - } - } - } - - private void EachList(Environment environment, DataValue value) - { - if (KeyName != null) - { - for (var i = 0; i < value.List.Count; i++) - { - environment[KeyName] = i; - environment[ValueName] = value.List[i]; - ExecuteChildren(environment); - } - } - else - { - foreach (var v in value.List) - { - environment[ValueName] = v; - ExecuteChildren(environment); - } - } - } - - private void ExecuteChildren(Environment environment) - { - foreach (var child in Children) - { - child.ExecuteIn(environment); - } - } - - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) - { - var value = Iterator.Compute(environment); - if (value.IsList) - { - EachList(environment, selectable, modifiable, value); - return; - } - - if (value.IsString) - { - EachString(environment, selectable, modifiable, value); - return; - } - - if (value.IsDictionary) - { - EachDictionary(environment, selectable, modifiable, value); - return; - } - - throw new InterpreterException(Coordinate, - $"cannot iterate over a value of type {value.Type.ToString().ToLowerInvariant()}"); - } - - private void EachDictionary(Environment environment, ISelectable selectable, IModifiable modifiable, DataValue value) - { - foreach (var (k, v) in value.Dictionary) - { - if (KeyName != null) - { - environment[KeyName] = k; - } - - environment[ValueName] = v; - ExecuteChildren(environment,selectable,modifiable); - } - } - - private void EachString(Environment environment, ISelectable selectable, IModifiable modifiable, DataValue value) - { - if (KeyName != null) - { - for (var i = 0; i < value.String.Length; i++) - { - environment[KeyName] = i; - environment[ValueName] = value.String[i]; - ExecuteChildren(environment,selectable,modifiable); - } - } - else - { - foreach (var v in value.String) - { - environment[ValueName] = v; - ExecuteChildren(environment,selectable,modifiable); - } - } - } - - private void EachList(Environment environment, ISelectable selectable, IModifiable modifiable, DataValue value) - { - if (KeyName != null) - { - for (var i = 0; i < value.List.Count; i++) - { - environment[KeyName] = i; - environment[ValueName] = value.List[i]; - ExecuteChildren(environment,selectable,modifiable); - } - } - else - { - foreach (var v in value.List) - { - environment[ValueName] = v; - ExecuteChildren(environment,selectable,modifiable); - } - } - } - - private void ExecuteChildren(Environment environment, ISelectable selectable, IModifiable modifiable) - { - foreach (var child in Children) - { - if (child is ISelectionAction selectionAction) - { - selectionAction.ExecuteOn(environment,selectable,modifiable); - } - else - { - child.ExecuteIn(environment); - } - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/For.cs b/src/PatchManager.SassyPatching/Nodes/Statements/For.cs deleted file mode 100644 index 238b876..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/For.cs +++ /dev/null @@ -1,346 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Nodes.Expressions; -using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements; - -/// -/// Represents a loop that iterates over a range of numbers -/// -public class For : Node, ISelectionAction -{ - /// - /// The variable that is set to the current iteration value - /// - public readonly string VariableName; - /// - /// The starting value of the iteration - /// - public readonly Expression InitialValue; - /// - /// Whether or not the loop is inclusive in its range - /// - public readonly bool Inclusive; - /// - /// The ending value of the iteration - /// - public readonly Expression EndingValue; - /// - /// The body of the iteration - /// - public readonly List Children; - - internal For(Coordinate c, string variableName, Expression initialValue, bool inclusive, Expression endingValue, List children) : base(c) - { - VariableName = variableName; - InitialValue = initialValue; - Inclusive = inclusive; - EndingValue = endingValue; - Children = children; - } - - /// - public override void ExecuteIn(Environment environment) - { - var start = InitialValue.Compute(environment); - var end = EndingValue.Compute(environment); - if (start.IsInteger) - { - SetupIntegerIteration(environment, end, start); - return; - } - - if (start.IsReal) - { - SetupRealIteration(environment, end, start); - return; - } - - throw new InterpreterException(Coordinate, $"cannot do a for loop w/ a value that is of type {start.Type.ToString().ToLowerInvariant()}"); - } - - private void SetupRealIteration(Environment environment, DataValue end, DataValue start) - { - Func endCheck; - bool inverted; - if (end.IsReal) - { - inverted = SetupRealRealIteration(end, start, out endCheck); - } - else if (end.IsInteger) - { - inverted = SetupRealIntegerIteration(end, start, out endCheck); - } - else - { - throw new InterpreterException(Coordinate, $"cannot do a for loop through/to a value of type {end.Type.ToString().ToLowerInvariant()}"); - } - - IterateReal(environment, start.Real, inverted, endCheck); - } - - private bool SetupRealIntegerIteration(DataValue end, DataValue start, out Func endCheck) - { - bool inverted; - inverted = start.Integer > end.Integer; - if (Inclusive) - { - if (inverted) - { - endCheck = l => l < end.Integer; - } - else - { - endCheck = l => l > end.Integer; - } - } - else - { - if (inverted) - { - endCheck = l => l <= end.Integer; - } - else - { - endCheck = l => l >= end.Integer; - } - } - - return inverted; - } - - private bool SetupRealRealIteration(DataValue end, DataValue start, out Func endCheck) - { - bool inverted; - inverted = start.Integer > end.Real; - if (Inclusive) - { - if (inverted) - { - endCheck = l => l < end.Real; - } - else - { - endCheck = l => l > end.Real; - } - } - else - { - if (inverted) - { - endCheck = l => l <= end.Real; - } - else - { - endCheck = l => l >= end.Real; - } - } - - return inverted; - } - - private void SetupIntegerIteration(Environment environment, DataValue end, DataValue start) - { - Func endCheck; - bool inverted; - if (end.IsReal) - { - inverted = SetupIntegerRealIteration(end, start, out endCheck); - } - else if (end.IsInteger) - { - inverted = SetupIntegerIntegerIteration(end, start, out endCheck); - } - else - { - throw new InterpreterException(Coordinate, $"cannot do a for loop through/to a value of type {end.Type.ToString().ToLowerInvariant()}"); - } - - IterateInteger(environment, start.Integer, inverted, endCheck); - } - - private bool SetupIntegerIntegerIteration(DataValue end, DataValue start, out Func endCheck) - { - bool inverted; - inverted = start.Integer > end.Integer; - if (Inclusive) - { - if (inverted) - { - endCheck = l => l < end.Integer; - } - else - { - endCheck = l => l > end.Integer; - } - } - else - { - if (inverted) - { - endCheck = l => l <= end.Integer; - } - else - { - endCheck = l => l >= end.Integer; - } - } - - return inverted; - } - - private bool SetupIntegerRealIteration(DataValue end, DataValue start, out Func endCheck) - { - bool inverted; - inverted = start.Integer > end.Real; - if (Inclusive) - { - if (inverted) - { - endCheck = l => l < end.Real; - } - else - { - endCheck = l => l > end.Real; - } - } - else - { - if (inverted) - { - endCheck = l => l <= end.Real; - } - else - { - endCheck = l => l >= end.Real; - } - } - - return inverted; - } - - - private void IterateInteger(Environment environment, long start, bool inverted, Func end) - { - while (!end(start)) - { - environment[VariableName] = start; - ExecuteChildren(environment); - start += inverted ? -1 : 1; - } - } - - private void IterateReal(Environment environment, double start, bool inverted, Func end) - { - while (!end(start)) - { - environment[VariableName] = start; - ExecuteChildren(environment); - start += inverted ? -1 : 1; - } - } - - - private void ExecuteChildren(Environment environment) - { - foreach (var child in Children) - { - child.ExecuteIn(environment); - } - } - - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) - { - var start = InitialValue.Compute(environment); - var end = EndingValue.Compute(environment); - if (start.IsInteger) - { - SetupIntegerIteration(environment, selectable, modifiable, end, start); - return; - } - - if (start.IsReal) - { - SetupRealIteration(environment, selectable, modifiable, end, start); - return; - } - - throw new InterpreterException(Coordinate, $"cannot do a for loop w/ a value that is of type {start.Type.ToString().ToLowerInvariant()}"); - } - private void SetupRealIteration(Environment environment, ISelectable selectable, IModifiable modifiable, DataValue end, DataValue start) - { - Func endCheck; - bool inverted; - if (end.IsReal) - { - inverted = SetupRealRealIteration(end, start, out endCheck); - } - else if (end.IsInteger) - { - inverted = SetupRealIntegerIteration(end, start, out endCheck); - } - else - { - throw new InterpreterException(Coordinate, $"cannot do a for loop through/to a value of type {end.Type.ToString().ToLowerInvariant()}"); - } - - IterateReal(environment, selectable, modifiable, start.Real, inverted, endCheck); - } - - private void SetupIntegerIteration(Environment environment, ISelectable selectable, IModifiable modifiable, DataValue end, DataValue start) - { - Func endCheck; - bool inverted; - if (end.IsReal) - { - inverted = SetupIntegerRealIteration(end, start, out endCheck); - } - else if (end.IsInteger) - { - inverted = SetupIntegerIntegerIteration(end, start, out endCheck); - } - else - { - throw new InterpreterException(Coordinate, $"cannot do a for loop through/to a value of type {end.Type.ToString().ToLowerInvariant()}"); - } - - IterateInteger(environment, selectable, modifiable, start.Integer, inverted, endCheck); - } - - - private void IterateInteger(Environment environment, ISelectable selectable, IModifiable modifiable, long start, bool inverted, Func end) - { - while (!end(start)) - { - environment[VariableName] = start; - ExecuteChildren(environment, selectable, modifiable); - start += inverted ? -1 : 1; - } - } - - private void IterateReal(Environment environment, ISelectable selectable, IModifiable modifiable, double start, bool inverted, Func end) - { - while (!end(start)) - { - environment[VariableName] = start; - ExecuteChildren(environment, selectable, modifiable); - start += inverted ? -1 : 1; - } - } - private void ExecuteChildren(Environment environment, ISelectable selectable, IModifiable modifiable) - { - foreach (var child in Children) - { - if (child is ISelectionAction selectionAction) - { - selectionAction.ExecuteOn(environment,selectable,modifiable); - } - else - { - child.ExecuteIn(environment); - } - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/FunctionLevel/Return.cs b/src/PatchManager.SassyPatching/Nodes/Statements/FunctionLevel/Return.cs deleted file mode 100644 index d0956be..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/FunctionLevel/Return.cs +++ /dev/null @@ -1,26 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Nodes.Expressions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.FunctionLevel; - -/// -/// Represents a function return statement -/// -public class Return : Node -{ - /// - /// The value to be returned from the function - /// - public readonly Expression ReturnedValue; - internal Return(Coordinate c, Expression returnedValue) : base(c) - { - ReturnedValue = returnedValue; - } - - /// - public override void ExecuteIn(Environment environment) - { - throw new FunctionReturnException(ReturnedValue.Compute(environment)); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionBlock.cs b/src/PatchManager.SassyPatching/Nodes/Statements/SelectionBlock.cs deleted file mode 100644 index 7a35133..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionBlock.cs +++ /dev/null @@ -1,201 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Nodes.Attributes; -using PatchManager.SassyPatching.Nodes.Expressions; -using PatchManager.SassyPatching.Nodes.Selectors; -using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements; - -/// -/// Represents a selection block -/// -public class SelectionBlock : Node, ISelectionAction -{ - /// - /// The attributes applied to this selection block - /// - public readonly List Attributes; - /// - /// The selector that this selection block matches - /// - public readonly Selector Selector; - /// - /// The actions to be taken upon a match - /// - public readonly List Actions; - - internal SelectionBlock(Coordinate c, List attributes, Selector selector, List actions) : base(c) - { - Attributes = attributes; - Selector = selector; - Actions = actions; - } - - - /// - /// Execute this selection block on a dataset - /// - /// The environment that contains this selection block - /// The type of dataset this is being executed (e.g. parts_data) - /// The dataset to execute this patch on - public bool ExecuteFresh(Environment snapshot, string datasetType, string name, ref string dataset) - { - // var subEnvironment = new Environment(snapshot.GlobalEnvironment, snapshot); - var selections = Selector.SelectAllTopLevel(datasetType, name, dataset, snapshot, out var rulesetMatchingObject); - - if (rulesetMatchingObject == null || selections.Count == 0) - { - return false; - } - // Get the first matching selection if there are somehow more than one - foreach (var selectable in selections) { - var modifiable = selectable.Selectable.OpenModification(); - var subEnvironment = new Environment(selectable.Environment.GlobalEnvironment, selectable.Environment); - if (modifiable != null) - { - subEnvironment["current"] = modifiable.Get(); - } - - foreach (var action in Actions) - { - if (action is ISelectionAction selectionAction) - { - selectionAction.ExecuteOn(subEnvironment, selectable.Selectable, modifiable); - } - else - { - action.ExecuteIn(subEnvironment); - } - } - - - } - var newDataSet = rulesetMatchingObject.Serialize(); - if (newDataSet == dataset) return false; - dataset = newDataSet; - return true; - - } - - public INewAsset ExecuteCreation(Environment snapshot, List arguments) - { - var selections = Selector.CreateNew(arguments, snapshot, out var resultingAsset); - foreach (var selectable in selections) { - var modifiable = selectable.Selectable.OpenModification(); - var subEnvironment = new Environment(selectable.Environment.GlobalEnvironment, selectable.Environment); - if (modifiable != null) - { - subEnvironment["current"] = modifiable.Get(); - } - - foreach (var action in Actions) - { - if (action is ISelectionAction selectionAction) - { - selectionAction.ExecuteOn(subEnvironment, selectable.Selectable, modifiable); - } - else - { - action.ExecuteIn(subEnvironment); - } - } - - } - return resultingAsset; - } - - - private void CreateGenerator(Environment environment, List arguments) - { - - foreach (var attribute in Attributes) - { - switch (attribute) - { - case RequireModAttribute requireModAttribute when - !requireModAttribute.Expression.Execute(environment.GlobalEnvironment.Universe.AllMods,environment): - return; - } - } - - var snapshot = environment.Snapshot(); - var args = arguments.Select(x => x.Compute(snapshot)).ToList(); - var generator = new SassyGenerator(snapshot, this, args); - environment.GlobalEnvironment.Universe.RegisterGenerator(generator); - } - /// - public override void ExecuteIn(Environment environment) - { - foreach (var attribute in Attributes) - { - switch (attribute) - { - case RequireModAttribute requireModAttribute when - !requireModAttribute.Expression.Execute(environment.GlobalEnvironment.Universe.AllMods,environment): - return; - case NewAttribute na: - CreateGenerator(environment, na.Arguments); - return; - } - } - var snapshot = environment.Snapshot(); - - var patcher = new SassyTextPatcher(snapshot, this); - environment.GlobalEnvironment.Universe.RegisterPatcherToUniverse(patcher); - } - - /// - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable = null) - { - foreach (var attribute in Attributes) - { - switch (attribute) - { - case RequireModAttribute requireModAttribute when - !requireModAttribute.Expression.Execute(environment.GlobalEnvironment.Universe.AllMods,environment): - return; - } - } - - var selections = Selector.SelectAll(new List { new() - { - Selectable = selectable, - Environment = new Environment(environment.GlobalEnvironment,environment.Snapshot()) - } }); - if (selections.Count == 0) return; - // Takes a snapshot of the parent in its current state - var parentValue = modifiable?.Get(); - foreach (var selection in selections) - { - ExecuteOnSingleSelection(selection.Environment, selection.Selectable, parentValue); - } - } - - private void ExecuteOnSingleSelection(Environment environment, ISelectable selection, DataValue parentDataValue) - { - var subModifiable = selection.OpenModification(); - var subEnvironment = new Environment(environment.GlobalEnvironment, environment) - { - ["current"] = selection.GetValue() - }; - - if (parentDataValue != null) - { - subEnvironment["parent"] = parentDataValue; - } - - foreach (var action in Actions) - { - if (action is ISelectionAction selectionAction) - { - selectionAction.ExecuteOn(subEnvironment, selection, subModifiable); - } - else - { - action.ExecuteIn(subEnvironment); - } - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/DeleteValue.cs b/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/DeleteValue.cs deleted file mode 100644 index 64b5e18..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/DeleteValue.cs +++ /dev/null @@ -1,30 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; - -/// -/// Represents a deletion selection action -/// -public class DeleteValue : Node, ISelectionAction -{ - internal DeleteValue(Coordinate c) : base(c) - { - } - - /// - public override void ExecuteIn(Environment environment) - { - } - - /// - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) - { - if (modifiable == null) - { - throw new InterpreterException(Coordinate, "Attempting to delete an unmodifiable selection"); - } - modifiable.Set(new DataValue(DataValue.DataType.Deletion)); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/Field.cs b/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/Field.cs deleted file mode 100644 index 22d9f00..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/Field.cs +++ /dev/null @@ -1,160 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Nodes.Expressions; -using PatchManager.SassyPatching.Nodes.Indexers; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; - -/// -/// Represents a field setting selection action -/// -public class Field : Node, ISelectionAction -{ - /// - /// The field to be set - /// - public readonly string FieldName; - /// - /// The index into the field, if there is one - /// - public readonly List Indexers; - /// - /// The value to set the field to - /// - public readonly Expression FieldValue; - internal Field(Coordinate c, string fieldName, List indexers, Expression fieldValue) : base(c) - { - FieldName = fieldName; - Indexers = indexers; - FieldValue = fieldValue; - } - - /// - public override void ExecuteIn(Environment environment) - { - } - - /// - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) - { - if (modifiable == null) - { - throw new InterpreterException(Coordinate, "Attempting to modify an unmodifiable selection"); - } - - var current = modifiable.GetFieldValue(FieldName); - var subEnv = new Environment(environment.GlobalEnvironment, environment); - modifiable.SetFieldValue(FieldName, ComputeValues(subEnv, current)); - } - private DataValue ComputeValues(Environment subEnv, DataValue current, int layer = 0) - { - if (Indexers.Count == layer) - { - subEnv["value"] = current; - return FieldValue.Compute(subEnv); - } - - var indexer = Indexers[layer]; - switch (indexer) - { - case SingleIndexer singleIndexer: - { - var index = singleIndexer.Index.Compute(subEnv); - if (index.IsInteger) - { - return ComputeIntegerIndex(subEnv, current, layer, index, indexer); - } - - if (index.IsString) - { - return ComputeStringIndex(subEnv, current, layer, index, indexer); - } - - throw new InterpreterException(indexer.Coordinate, - $"Invalid index type {index.Type}, expected Integer or String"); - } - case EverythingIndexer everythingIndexer: - return current.Type switch - { - DataValue.DataType.List => current.List.Select(value => ComputeValues(subEnv, value, layer + 1)) - .ToList(), - DataValue.DataType.Dictionary => current.Dictionary - .Select(kv => (kv.Key, ComputeValues(subEnv, kv.Value, layer + 1))) - .ToDictionary(kv => kv.Key, kv => kv.Item2), - DataValue.DataType.None => DataValue.Null, - _ => throw new InterpreterException(everythingIndexer.Coordinate, - $"Attempting to use a `*` indexer on a value of type {current.Type}") - }; - default: - throw new InterpreterException(indexer.Coordinate, $"Unknown indexer type: {indexer.GetType()}"); - } - } - - private DataValue ComputeStringIndex( - Environment subEnv, - DataValue current, - int layer, - DataValue index, - Node indexer - ) - { - // ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault - return current.Type switch - { - DataValue.DataType.None => new Dictionary - { - [index.String] = ComputeValues(subEnv, DataValue.Null, layer + 1) - }, - DataValue.DataType.Dictionary => new Dictionary(current.Dictionary) - { - [index.String] = ComputeValues(subEnv, - current.Dictionary.TryGetValue(index.String, out var currentValue) - ? currentValue - : DataValue.Null, layer + 1), - }, - _ => throw new InterpreterException(indexer.Coordinate, - $"Attempting to index into a value of type {current.Type} with an indexer that is a String") - }; - } - - private DataValue ComputeIntegerIndex( - Environment subEnv, - DataValue current, - int layer, - DataValue index, - Node indexer - ) - { - // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault - switch (current.Type) - { - case DataValue.DataType.None: - { - var list = new List(); - for (var i = 0; i < index.Integer; i++) - { - list.Add(DataValue.Null); - } - - list.Add(ComputeValues(subEnv, DataValue.Null, layer + 1)); - return list; - } - case DataValue.DataType.List: - { - var list = new List(current.List); - while (list.Count <= (int)index.Integer) - { - list.Add(DataValue.Null); - } - - list[(int)index.Integer] = ComputeValues(subEnv, list[(int)index.Integer], layer + 1); - return list; - } - default: - throw new InterpreterException(indexer.Coordinate, - $"Attempting to index into a value of type {current.Type} with an indexer that is an Integer"); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/ISelectionAction.cs b/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/ISelectionAction.cs deleted file mode 100644 index 9410cad..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/ISelectionAction.cs +++ /dev/null @@ -1,19 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; - -/// -/// This represents a selection action to be taken on a selection -/// -public interface ISelectionAction -{ - /// - /// Execute this selection action on a selectable - /// - /// The environment that this action is taking place in - /// The selectable that this action is being acted upon - /// The modifiable state of the selectable, null if its not modifiable - public void ExecuteOn(Environment environment, ISelectable selectable, [CanBeNull] IModifiable modifiable); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MergeValue.cs b/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MergeValue.cs deleted file mode 100644 index adeb64a..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MergeValue.cs +++ /dev/null @@ -1,56 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Nodes.Expressions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; - -/// -/// Represents a merge selection action -/// -public class MergeValue : Node, ISelectionAction -{ - /// - /// The value the selection is going to be merged with, should evaluate to a dictionary - /// - public readonly Expression Value; - internal MergeValue(Coordinate c, Expression value) : base(c) - { - Value = value; - } - - /// - public override void ExecuteIn(Environment environment) - { - } - - /// - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) - { - if (modifiable == null) - { - throw new InterpreterException(Coordinate, "Attempting to merge non modifiable selection"); - } - - var value = modifiable.Get(); - var subEnvironment = new Environment(environment.GlobalEnvironment, environment) - { - ["value"] = value - }; - var toMerge = Value.Compute(subEnvironment); - if (value.IsDictionary && toMerge.IsDictionary) - { - foreach (var kv in toMerge.Dictionary) - { - value.Dictionary[kv.Key] = kv.Value; - } - - modifiable.Set(value); - } - else - { - throw new BinaryExpressionTypeException(Coordinate, "merge", value.Type.ToString(), - toMerge.Type.ToString()); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MixinBlockInclude.cs b/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MixinBlockInclude.cs deleted file mode 100644 index 75c44e3..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MixinBlockInclude.cs +++ /dev/null @@ -1,61 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; - -/// -/// Represents a mixin block include (i.e. slotting actions into a mixin) -/// -public class MixinBlockInclude : Node, ISelectionAction -{ - /// - /// The name of the mixin being included - /// - public readonly string MixinName; - /// - /// The list of arguments to the mixin being included - /// - public readonly List Arguments; - - /// - /// The actions to be slotted into the mixin - /// - public readonly List SlotActions; - - internal MixinBlockInclude(Coordinate c, string mixinName, List arguments, List slotActions) : base(c) - { - MixinName = mixinName; - Arguments = arguments; - SlotActions = slotActions; - } - - /// - public override void ExecuteIn(Environment environment) - { - } - - /// - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) - { - if (environment.GlobalEnvironment.AllMixins.TryGetValue(MixinName, out var mixin)) - { - try - { - var subEnv = new Environment(environment.GlobalEnvironment, environment) - { - SlotActions = SlotActions - }; - mixin.Include(subEnv,Arguments.Select(x => x.Compute(environment)).ToList(),selectable,modifiable); - } - catch (InvocationException e) - { - throw new InterpreterException(Coordinate, e.ToString()); - } - } - else - { - throw new InterpreterException(Coordinate, $"{MixinName} is not a valid mixin"); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MixinInclude.cs b/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MixinInclude.cs deleted file mode 100644 index 7f2d215..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MixinInclude.cs +++ /dev/null @@ -1,51 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; - -/// -/// Represents a mixin inclusion -/// -public class MixinInclude : Node, ISelectionAction -{ - /// - /// The name of the mixin being included - /// - public readonly string MixinName; - /// - /// The list of arguments to the mixin being included - /// - public readonly List Arguments; - - internal MixinInclude(Coordinate c, string mixinName, List arguments) : base(c) - { - MixinName = mixinName; - Arguments = arguments; - } - - /// - public override void ExecuteIn(Environment environment) - { - } - - /// - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) - { - if (environment.GlobalEnvironment.AllMixins.TryGetValue(MixinName, out var mixin)) - { - try - { - mixin.Include(environment,Arguments.Select(x => x.Compute(environment)).ToList(),selectable,modifiable); - } - catch (InvocationException e) - { - throw new InterpreterException(Coordinate, e.ToString()); - } - } - else - { - throw new InterpreterException(Coordinate, $"{MixinName} is not a valid mixin"); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MixinSlot.cs b/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MixinSlot.cs deleted file mode 100644 index 9f86582..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/MixinSlot.cs +++ /dev/null @@ -1,33 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Interfaces; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; - -public class MixinSlot(Coordinate c) : Node(c), ISelectionAction -{ - public override void ExecuteIn(Environment environment) - { - } - - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) - { - var actions = environment.SlotActions; - if (actions == null) - { - throw new InterpreterException(Coordinate, "Attempting to insert into a mixin slot without there being any actions passed for this purpose"); - } - - foreach (var action in actions) - { - if (action is ISelectionAction selectionAction) - { - selectionAction.ExecuteOn(environment, selectable, modifiable); - } - else - { - action.ExecuteIn(environment); - } - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/SetValue.cs b/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/SetValue.cs deleted file mode 100644 index fcade14..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/SelectionLevel/SetValue.cs +++ /dev/null @@ -1,44 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Nodes.Expressions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; - -/// -/// Represents a value setting selection action -/// -public class SetValue : Node, ISelectionAction -{ - /// - /// The value to set the selection to - /// - public readonly Expression Value; - internal SetValue(Coordinate c, Expression value) : base(c) - { - Value = value; - } - - /// - public override void ExecuteIn(Environment environment) - { - throw new NotImplementedException(); - } - - /// - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) - { - if (modifiable == null) - { - throw new InterpreterException(Coordinate, "Attempting to set a non modifiable selection"); - } - - var value = modifiable.Get(); - var subEnvironment = new Environment(environment.GlobalEnvironment, environment) - { - ["value"] = value - }; - var result = Value.Compute(subEnvironment); - modifiable.Set(result); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/ConfigCreation.cs b/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/ConfigCreation.cs deleted file mode 100644 index b653951..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/ConfigCreation.cs +++ /dev/null @@ -1,37 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Nodes.Expressions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel; - -public class ConfigCreation : Node -{ - public string ConfigLabel; - public string ConfigName; - public Expression ConfigValue; - public ConfigCreation(Coordinate c, string configLabel, string configName, Expression configValue) : base(c) - { - ConfigLabel = configLabel; - ConfigName = configName; - ConfigValue = configValue; - } - public override void ExecuteIn(Environment environment) - { - var configLabel = ""; - var configName = ""; - try - { - configLabel = ConfigLabel.Interpolate(environment); - configName = ConfigName.Interpolate(environment); - } - catch (Exception e) - { - throw new InterpolationException(Coordinate, e.Message); - } - - var universe = environment.GlobalEnvironment.Universe; - if (!universe.Configs.TryGetValue(configLabel, out var label)) - label = universe.Configs[configLabel] = new Dictionary(); - label[configName] = ConfigValue.Compute(environment); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/ConfigUpdate.cs b/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/ConfigUpdate.cs deleted file mode 100644 index fda1eef..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/ConfigUpdate.cs +++ /dev/null @@ -1,31 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Nodes.Expressions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel; - -public class ConfigUpdate : Node -{ - public Expression Priority; - public String Label; - [CanBeNull] public String Name; - public Expression UpdateExpression; - public ConfigUpdate(Coordinate c, Expression priority, string label, [CanBeNull] string name, Expression updateExpression) : base(c) - { - Priority = priority; - Label = label; - Name = name; - UpdateExpression = updateExpression; - } - public override void ExecuteIn(Environment environment) - { - var universe = environment.GlobalEnvironment.Universe; - var priority = Priority.Compute(environment); - if (!priority.IsInteger) - { - throw new InterpreterException(Coordinate, "The priority for a config update must be an integer"); - } - universe.AddConfigUpdater(priority.Integer,Label,Name,UpdateExpression,environment.Snapshot()); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/Function.cs b/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/Function.cs deleted file mode 100644 index 000100e..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/Function.cs +++ /dev/null @@ -1,38 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel; - -/// -/// Represents a function definition -/// -public class Function : Node -{ - /// - /// The name of the function - /// - public readonly string Name; - /// - /// The list of arguments the function takes - /// - public readonly List Arguments; - /// - /// The list of statements to be executed upon a function call - /// - public readonly List Body; - internal Function(Coordinate c, string name, List arguments, List body) : base(c) - { - Name = name; - Arguments = arguments; - Body = body; - } - - // Don't register functions just yet - /// - public override void ExecuteIn(Environment environment) - { - // We register this function as if its alone in its environment and cannot react to the changes of variables outside of its scope - var snapshot = environment.Snapshot(); - environment.GlobalEnvironment.AllFunctions[Name] = new SassyPatchFunction(snapshot, this); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/Import.cs b/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/Import.cs deleted file mode 100644 index 4b2ffae..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/Import.cs +++ /dev/null @@ -1,48 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel; - -/// -/// Represents a library import -/// -public class Import : Node -{ - /// - /// - /// The library being imported, can take a few formats - /// - /// - /// Local library: "name", imports a local (to the patch folder for the mod) file named "_name" or if there is any pathing it only prepends the underscore after the last slash - /// - /// - /// External library: "guid:name", imports a file from another mod (defined in the guid) named "_name" - /// - /// - /// Builtin library: "builtin:name", imports a builtin library named "name" - /// - /// - public readonly string Library; - - internal Import(Coordinate c, string library) : base(c) - { - Library = library; - } - - /// - public override void ExecuteIn(Environment environment) - { - try - { - environment.GlobalEnvironment.Import(environment, Library.Interpolate(environment)); - } - catch (ImportException) - { - throw new InterpreterException(Coordinate, $"Cannot import library {Library.Interpolate(environment)} as it does not exist"); - } - catch (Exception e) - { - throw new InterpolationException(Coordinate, e.Message); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/Mixin.cs b/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/Mixin.cs deleted file mode 100644 index 4bce6cb..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/Mixin.cs +++ /dev/null @@ -1,35 +0,0 @@ -using PatchManager.SassyPatching.Execution; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel; - -/// -/// Represents a selection block mixin -/// -public class Mixin : Node -{ - /// - /// The name of the mixin - /// - public readonly string Name; - /// - /// The arguments that the mixin takes - /// - public readonly List Arguments; - /// - /// The list of nodes to be "mixed in" when included - /// - public readonly List Body; - internal Mixin(Coordinate c, string name, List arguments, List body) : base(c) - { - Name = name; - Arguments = arguments; - Body = body; - } - - /// - public override void ExecuteIn(Environment environment) - { - environment.GlobalEnvironment.AllMixins[Name] = new PatchMixin(this); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/PatchDeclaration.cs b/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/PatchDeclaration.cs deleted file mode 100644 index 734b906..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/PatchDeclaration.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel; - -/// -/// Represents a declaration of which labels to patch -/// -public class PatchDeclaration : Node -{ - /// - /// The labels to patch - /// - public List Labels; - - internal PatchDeclaration(Coordinate c, List labels) : base(c) => Labels = labels; - - /// - public override void ExecuteIn(Environment environment) - { - environment.GlobalEnvironment.Universe.PatchLabels(Labels.Select(label => label.Interpolate(environment)).ToArray()); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/StageDefinition.cs b/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/StageDefinition.cs deleted file mode 100644 index 57229fb..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/StageDefinition.cs +++ /dev/null @@ -1,107 +0,0 @@ -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Execution; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel; - -public class StageDefinition : Node -{ - - public string Name; - public bool Implicit; - public bool Global; - public List Before; - public List After; - public StageDefinition(Coordinate c, string name) : base(c) - { - Name = name; - Implicit = true; - Global = false; - Before = new(); - After = new(); - } - - public StageDefinition(Coordinate c, string name, bool global) : base(c) - { - Name = name; - Global = global; - Implicit = !global; - Before = new(); - After = new(); - } - - public StageDefinition(Coordinate c, string name, List attributes) : base(c) - { - Name = name; - Global = false; - Implicit = false; - Before = new(); - After = new(); - foreach (var attribute in attributes) - { - if (attribute.After) - After.Add(attribute.Relative); - else - Before.Add(attribute.Relative); - } - } - - public override void ExecuteIn(Environment environment) - { - var universe = environment.GlobalEnvironment.Universe; - var id = environment.GlobalEnvironment.ModGuid; - var interpName = ""; - try - { - interpName = Name.Interpolate(environment); - } - catch (Exception e) - { - throw new InterpolationException(Coordinate, e.Message); - } - var name = $"{id}:{interpName}"; - var stage = new Stage(); - if (Global) // @global - { - stage.RunsAfter.Add(universe.LastImplicitGlobal); - universe.LastImplicitGlobal = name; - } else if (Implicit) // implicit - { - stage.RunsAfter.Add(universe.LastImplicitWithinMod[id]); - var post = universe.UnsortedStages[$"{id}:post"]; - post.RunsAfter.Clear(); - post.RunsAfter.Add(name); - universe.LastImplicitWithinMod[id] = name; - } - else // defined relations - { - stage.RunsAfter.AddRange(After.Select(x => - { - var interp = ""; - try - { - interp = x.Interpolate(environment); - } - catch (Exception e) - { - throw new InterpolationException(Coordinate, e.Message); - } - return (interp.Contains(":") || universe.AllMods.Contains(interp)) ? interp : $"{id}:{interp}"; - })); - stage.RunsBefore.AddRange(Before.Select(x => - { - var interp = ""; - try - { - interp = x.Interpolate(environment); - } - catch (Exception e) - { - throw new InterpolationException(Coordinate, e.Message); - } - return (interp.Contains(":") || universe.AllMods.Contains(interp)) ? interp : $"{id}:{interp}"; - })); - } - universe.UnsortedStages[name] = stage; - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/StageDefinitionAttribute.cs b/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/StageDefinitionAttribute.cs deleted file mode 100644 index 0e14979..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/TopLevel/StageDefinitionAttribute.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements.TopLevel; - -public class StageDefinitionAttribute : Node -{ - public string Relative; - public bool After; - public StageDefinitionAttribute(Coordinate c, string relative, bool after) : base(c) - { - Relative = relative; - After = after; - } - public override void ExecuteIn(Environment environment) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/VariableDeclaration.cs b/src/PatchManager.SassyPatching/Nodes/Statements/VariableDeclaration.cs deleted file mode 100644 index ea65cb2..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/VariableDeclaration.cs +++ /dev/null @@ -1,164 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.SassyPatching.Exceptions; -using PatchManager.SassyPatching.Nodes.Expressions; -using PatchManager.SassyPatching.Nodes.Indexers; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements; - -/// -/// Represents a variable declaration -/// -public class VariableDeclaration : Node -{ - /// - /// The name of the variable being declared - /// - public readonly string Variable; - - /// - /// The list of indexers for list creation/indexing - /// - public readonly List Indexers; - - /// - /// The value being assigned to the variable - /// - public readonly Expression Value; - - - internal VariableDeclaration(Coordinate c, string variable, List indexers, Expression value) : base(c) - { - Variable = variable; - Indexers = indexers; - Value = value; - } - - /// - public override void ExecuteIn(Environment environment) - { - var subEnv = new Environment(environment.GlobalEnvironment, environment); - var current = DataValue.Null; - try - { - current = environment[Variable]; - } - catch - { - // Ignored - } - - var result = ComputeValues(subEnv, current); - environment[Variable] = result; - } - - private DataValue ComputeValues(Environment subEnv, DataValue current, int layer = 0) - { - if (Indexers.Count == layer) - { - subEnv["value"] = current; - return Value.Compute(subEnv); - } - - var indexer = Indexers[layer]; - switch (indexer) - { - case SingleIndexer singleIndexer: - { - var index = singleIndexer.Index.Compute(subEnv); - if (index.IsInteger) - { - return ComputeIntegerIndex(subEnv, current, layer, index, indexer); - } - - if (index.IsString) - { - return ComputeStringIndex(subEnv, current, layer, index, indexer); - } - - throw new InterpreterException(indexer.Coordinate, - $"Invalid index type {index.Type}, expected Integer or String"); - } - case EverythingIndexer everythingIndexer: - return current.Type switch - { - DataValue.DataType.List => current.List.Select(value => ComputeValues(subEnv, value, layer + 1)) - .ToList(), - DataValue.DataType.Dictionary => current.Dictionary - .Select(kv => (kv.Key, ComputeValues(subEnv, kv.Value, layer + 1))) - .ToDictionary(kv => kv.Key, kv => kv.Item2), - DataValue.DataType.None => DataValue.Null, - _ => throw new InterpreterException(everythingIndexer.Coordinate, - $"Attempting to use a `*` indexer on a value of type {current.Type}") - }; - default: - throw new InterpreterException(indexer.Coordinate, $"Unknown indexer type: {indexer.GetType()}"); - } - } - - private DataValue ComputeStringIndex( - Environment subEnv, - DataValue current, - int layer, - DataValue index, - Node indexer - ) - { - // ReSharper disable once SwitchExpressionHandlesSomeKnownEnumValuesWithExceptionInDefault - return current.Type switch - { - DataValue.DataType.None => new Dictionary - { - [index.String] = ComputeValues(subEnv, DataValue.Null, layer + 1) - }, - DataValue.DataType.Dictionary => new Dictionary(current.Dictionary) - { - [index.String] = ComputeValues(subEnv, - current.Dictionary.TryGetValue(index.String, out var currentValue) - ? currentValue - : DataValue.Null, layer + 1), - }, - _ => throw new InterpreterException(indexer.Coordinate, - $"Attempting to index into a value of type {current.Type} with an indexer that is a String") - }; - } - - private DataValue ComputeIntegerIndex( - Environment subEnv, - DataValue current, - int layer, - DataValue index, - Node indexer - ) - { - // ReSharper disable once SwitchStatementHandlesSomeKnownEnumValuesWithDefault - switch (current.Type) - { - case DataValue.DataType.None: - { - var list = new List(); - for (var i = 0; i < index.Integer; i++) - { - list.Add(DataValue.Null); - } - - list.Add(ComputeValues(subEnv, DataValue.Null, layer + 1)); - return list; - } - case DataValue.DataType.List: - { - var list = new List(current.List); - while (list.Count <= (int)index.Integer) - { - list.Add(DataValue.Null); - } - - list[(int)index.Integer] = ComputeValues(subEnv, list[(int)index.Integer], layer + 1); - return list; - } - default: - throw new InterpreterException(indexer.Coordinate, - $"Attempting to index into a value of type {current.Type} with an indexer that is an Integer"); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Nodes/Statements/While.cs b/src/PatchManager.SassyPatching/Nodes/Statements/While.cs deleted file mode 100644 index f928f91..0000000 --- a/src/PatchManager.SassyPatching/Nodes/Statements/While.cs +++ /dev/null @@ -1,56 +0,0 @@ -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Nodes.Expressions; -using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Nodes.Statements; - -/// -/// Represents a loop that iterates while a condition remains true -/// -public class While : Node, ISelectionAction -{ - /// - /// The condition to test - /// - public readonly Expression Condition; - /// - /// The body to iterate - /// - public readonly List Children; - internal While(Coordinate c, Expression condition, List children) : base(c) - { - Condition = condition; - Children = children; - } - - /// - public override void ExecuteIn(Environment environment) - { - while (Condition.Compute(environment).Truthy) - { - foreach (var child in Children) - { - child.ExecuteIn(environment); - } - } - } - - public void ExecuteOn(Environment environment, ISelectable selectable, IModifiable modifiable) - { - while (Condition.Compute(environment).Truthy) - { - foreach (var child in Children) - { - if (child is ISelectionAction selectionAction) - { - selectionAction.ExecuteOn(environment,selectable,modifiable); - } - else - { - child.ExecuteIn(environment); - } - } - } - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/PatchManager.SassyPatching.csproj b/src/PatchManager.SassyPatching/PatchManager.SassyPatching.csproj deleted file mode 100644 index 555c154..0000000 --- a/src/PatchManager.SassyPatching/PatchManager.SassyPatching.csproj +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - $(NoWarn);CS3021;CS1591;CS0168;CS1571;CS1573 - - diff --git a/src/PatchManager.SassyPatching/Selectables/JTokenSelectable.cs b/src/PatchManager.SassyPatching/Selectables/JTokenSelectable.cs deleted file mode 100644 index e653018..0000000 --- a/src/PatchManager.SassyPatching/Selectables/JTokenSelectable.cs +++ /dev/null @@ -1,130 +0,0 @@ -using JetBrains.Annotations; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Modifiables; - -namespace PatchManager.SassyPatching.Selectables; - -/// -/// Represents a selectable that operates over objects -/// -public class JTokenSelectable : BaseSelectable -{ - private readonly Action _markDirty; - /// - /// This is the token being modified - /// - protected readonly JToken Token; - - /// - /// Create a new JToken Selectable - /// - /// How this should notify that it has been modified - /// The token this operates over - /// The name/element this is coming from - /// The type of element this is, can be different from the name - public JTokenSelectable(Action markDirty, JToken token, string name, [CanBeNull] string elementType = null) - { - _markDirty = markDirty; - Token = token; - ElementType = elementType ?? name; - _getName = _ => name; - Classes = new List(); - Children = new List(); - foreach (var subToken in token) - { - if (subToken is not JProperty property) continue; - Classes.Add(property.Name); - Children.Add(new JTokenSelectable(markDirty,property.Value,property.Name)); - } - } - - /// - /// Create a new JToken Selectable - /// - /// How this should notify that it has been modified - /// The token this operates over - /// The function used to get the name of this token - /// The type of element this is, can be different from the name - public JTokenSelectable(Action markDirty, JToken token, Func name, [CanBeNull] string elementType = null) - { - _markDirty = markDirty; - Token = token; - ElementType = elementType ?? name(token); - _getName = name; - Classes = new(); - Children = new(); - foreach (var subToken in token) - { - if (subToken is not JProperty property) continue; - Classes.Add(property.Name); - Children.Add(new JTokenSelectable(markDirty,property.Value,property.Name)); - } - } - - /// - public sealed override List Children { get; } - - private readonly Func _getName; - - /// - public override string Name => _getName.Invoke(Token); - - /// - public sealed override List Classes { get; } - - public override bool MatchesClass(string @class, out DataValue classValue) - { - classValue = null; - if (!MatchesClass(@class)) - { - return false; - } - - classValue = DataValue.FromJToken(Token[@class]); - return true; - - } - - /// - public override string ElementType { get; } - - /// - public override bool IsSameAs(ISelectable other) => - other is JTokenSelectable jTokenSelectable && jTokenSelectable.Token == Token; - - /// - public override IModifiable OpenModification() - { - return new JTokenModifiable(Token,_markDirty); - } - - /// - public override ISelectable AddElement(string elementType) - { - var obj = new JObject(); - var token = Token; - while (token is JProperty prop) - token = prop.Value; - switch (token) - { - case JArray jArray: - jArray.Add(obj); - break; - case JObject jObject: - jObject[elementType] = obj; - break; - default: - throw new InvalidOperationException(); - } - var n = new JTokenSelectable(_markDirty, obj, elementType); - Children.Add(n); - return n; - } - - /// - public override string Serialize() => Token.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(Token); -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/SelectionUtilities.cs b/src/PatchManager.SassyPatching/SelectionUtilities.cs deleted file mode 100644 index 73c8133..0000000 --- a/src/PatchManager.SassyPatching/SelectionUtilities.cs +++ /dev/null @@ -1,19 +0,0 @@ -using PatchManager.SassyPatching.Execution; - -namespace PatchManager.SassyPatching; - -internal static class SelectionUtilities -{ - public static List CombineSelections(List a, List b) - { - var combination = a.ToList(); - combination.AddRange(b.Where(y => !combination.Any(x => x.Selectable.IsSameAs(y.Selectable)))); - return combination; - } - - public static List IntersectSelections(List a, List b) - { - return a.Where(x => b.Any(y => x.Selectable.IsSameAs(y.Selectable))).ToList(); - } - -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Transformer.cs b/src/PatchManager.SassyPatching/Transformer.cs deleted file mode 100644 index 30a99d0..0000000 --- a/src/PatchManager.SassyPatching/Transformer.cs +++ /dev/null @@ -1,820 +0,0 @@ -using System.Globalization; -using PatchManager.SassyPatching.Nodes; -using PatchManager.SassyPatching.Nodes.Attributes; -using PatchManager.SassyPatching.Nodes.Attributes.RequireExpressions; -using PatchManager.SassyPatching.Nodes.Expressions; -using PatchManager.SassyPatching.Nodes.Expressions.Binary; -using PatchManager.SassyPatching.Nodes.Expressions.Unary; -using PatchManager.SassyPatching.Nodes.Indexers; -using PatchManager.SassyPatching.Nodes.Selectors; -using PatchManager.SassyPatching.Nodes.Statements; -using PatchManager.SassyPatching.Nodes.Statements.FunctionLevel; -using PatchManager.SassyPatching.Nodes.Statements.SelectionLevel; -using PatchManager.SassyPatching.Nodes.Statements.TopLevel; -using SassyPatchGrammar; -using UnityEngine; - -namespace PatchManager.SassyPatching; - -/// -/// A class used for transforming an Antlr representation of a Patch to our own node tree representation -/// -public class Transformer : sassy_parserBaseVisitor -{ - private readonly Action _logError; - - /// - /// Whether the transformation encountered an error - /// - public bool Errored; - - /// - /// Creates a new transformer - /// - /// The function called when an error is encountered - public Transformer(Action logError) - { - _logError = logError; - } - - private Node Error(Coordinate location, string error) - { - _logError($"{location.ToString()}: {error}"); - Errored = true; - return new ErrorNode(location, error); - } - - /// - public override Node VisitPatch(sassy_parser.PatchContext context) => - new SassyPatch(context.GetCoordinate(), - context.top_level_statement().Select(Visit) - .ToList()); - - /// - public override Node VisitPatch_declaration(sassy_parser.Patch_declarationContext context) - { - var labels = context.patch_list().sassy_string().Select(x => x.GetStringValue()).ToList(); - return new PatchDeclaration(context.GetCoordinate(), labels); - } - - /// - public override Node VisitImport_declaration(sassy_parser.Import_declarationContext context) => - new Import(context.GetCoordinate(), - context.imp.GetStringValue()); - - /// - public override Node VisitNormal_var_decl(sassy_parser.Normal_var_declContext context) - => new VariableDeclaration(context.GetCoordinate(), - context.variable.Text.TrimFirst(), - context.index().Select(Visit).Cast().ToList(), - Visit(context.val) as Expression); - - /// - public override Node VisitAdd_var_decl(sassy_parser.Add_var_declContext context) => new VariableDeclaration( - context.GetCoordinate(), - context.variable.Text.TrimFirst(), - context.index().Select(Visit).Cast().ToList(), - new ImplicitAdd(context.GetCoordinate(), Visit(context.val) as Expression)); - - /// - public override Node VisitSubtract_var_decl(sassy_parser.Subtract_var_declContext context) => - new VariableDeclaration( - context.GetCoordinate(), - context.variable.Text.TrimFirst(), - context.index().Select(Visit).Cast().ToList(), - new ImplicitSubtract(context.GetCoordinate(), Visit(context.val) as Expression)); - - /// - public override Node VisitMultiply_var_decl(sassy_parser.Multiply_var_declContext context) => - new VariableDeclaration( - context.GetCoordinate(), - context.variable.Text.TrimFirst(), - context.index().Select(Visit).Cast().ToList(), - new ImplicitMultiply(context.GetCoordinate(), Visit(context.val) as Expression)); - - /// - public override Node VisitDivide_var_decl(sassy_parser.Divide_var_declContext context) => new VariableDeclaration( - context.GetCoordinate(), - context.variable.Text.TrimFirst(), - context.index().Select(Visit).Cast().ToList(), - new ImplicitDivide(context.GetCoordinate(), Visit(context.val) as Expression)); - - /// - public override Node VisitFunction_def(sassy_parser.Function_defContext context) => - new Function(context.GetCoordinate(), - context.name.Text, - context.args.arg_decl() - .Select(Visit) - .Cast() - .ToList(), - context.body.function_statement().Select(Visit) - .ToList()); - - /// - public override Node VisitClosure(sassy_parser.ClosureContext context) => - new Closure(context.GetCoordinate(), - context.args.arg_decl() - .Select(Visit) - .Cast() - .ToList(), - context.body.function_statement().Select(Visit) - .ToList()); - - /// - public override Node VisitMixin_def(sassy_parser.Mixin_defContext context) => - new Mixin(context.GetCoordinate(), - context.name.Text, - context.args.arg_decl() - .Select(Visit) - .Cast() - .ToList(), - context.body.selector_statement().Select(Visit) - .ToList()); - - /// - public override Node VisitTop_level_conditional(sassy_parser.Top_level_conditionalContext context) - { - Node @else = null; - if (context.els != null) - { - @else = Visit(context.els); - } - - return new Conditional(context.GetCoordinate(), - Visit(context.cond) as Expression, - context.top_level_statement() - .Select(Visit) - .ToList(), - @else); - } - - /// - public override Node VisitTop_level_else_else(sassy_parser.Top_level_else_elseContext context) => - new Block(context.GetCoordinate(), - context.top_level_statement() - .Select(Visit) - .ToList()); - - /// - public override Node VisitTop_level_else_if(sassy_parser.Top_level_else_ifContext context) - { - Node @else = null; - if (context.els != null) - { - @else = Visit(context.els); - } - - return new Conditional(context.GetCoordinate(), - Visit(context.cond) as Expression, - context.top_level_statement() - .Select(Visit) - .ToList(), - @else); - } - - /// - public override Node VisitSelection_block(sassy_parser.Selection_blockContext context) => - new SelectionBlock(context.GetCoordinate(), - context.attributed_selector() - .attribute() - .Select(Visit) - .Cast() - .ToList(), - Visit(context.attributed_selector() - .selector()) as Selector, - context.selector_body() - .selector_statement().Select(Visit) - .ToList()); - - /// - public override Node VisitRequire_mod(sassy_parser.Require_modContext context) => - new RequireModAttribute(context.GetCoordinate(), Visit(context.expr) as RequireExpression); - - public override Node VisitRequire_not(sassy_parser.Require_notContext context) => - new RequireNot(context.GetCoordinate(), Visit(context.internal_expr) as RequireExpression); - - public override Node VisitRequire_and(sassy_parser.Require_andContext context) => - new RequireAnd(context.GetCoordinate(), Visit(context.lhs) as RequireExpression, - Visit(context.rhs) as RequireExpression); - - public override Node VisitRequire_or(sassy_parser.Require_orContext context) => - new RequireOr(context.GetCoordinate(), Visit(context.lhs) as RequireExpression, - Visit(context.rhs) as RequireExpression); - - public override Node VisitRequire_guid(sassy_parser.Require_guidContext context) => - new RequireGuid(context.GetCoordinate(), context.modid.GetStringValue()); - - /// - public override Node VisitRun_at_stage(sassy_parser.Run_at_stageContext context) => - new RunAtStageAttribute(context.GetCoordinate(), context.stage.GetStringValue()); - - public override Node VisitNew_asset(sassy_parser.New_assetContext context) - { - var expressions = context.constructor_arguments().expression().Select(Visit).Cast().ToList(); - return new NewAttribute(context.GetCoordinate(), expressions); - } - - /// - public override Node VisitSel_element(sassy_parser.Sel_elementContext context) - => new ElementSelector(context.GetCoordinate(), context.ELEMENT().GetText()); - - public override Node VisitSel_element_string(sassy_parser.Sel_element_stringContext context) => - new ElementSelector(context.GetCoordinate(), context.STRING().GetText().Unescape()); - - /// - public override Node VisitSel_ruleset(sassy_parser.Sel_rulesetContext context) - => new RulesetSelector(context.GetCoordinate(), context.RULESET().GetText().TrimFirst()); - - - /// - public override Node VisitSel_class_capture(sassy_parser.Sel_class_captureContext context) => - new ClassCaptureSelector(context.GetCoordinate(), context.CLASS().GetText().TrimFirst(), - context.function_statement().Select(Visit).ToList()); - - /// - public override Node VisitSel_string_class_capture(sassy_parser.Sel_string_class_captureContext context) => - new ClassCaptureSelector(context.GetCoordinate(), context.STRING_CLASS().GetText().TrimFirst().Unescape(), - context.function_statement().Select(Visit).ToList()); - - /// - public override Node VisitSel_child(sassy_parser.Sel_childContext context) - => new ChildSelector(context.GetCoordinate(), Visit(context.parent) as Selector, - Visit(context.child) as Selector); - - /// - public override Node VisitSel_add_element(sassy_parser.Sel_add_elementContext context) - => new ElementAdditionSelector(context.GetCoordinate(), context.ELEMENT().GetText()); - - /// - public override Node VisitSel_add_string_element(sassy_parser.Sel_add_string_elementContext context) - => new ElementAdditionSelector(context.GetCoordinate(), context.STRING().GetText().Unescape()); - - /// - public override Node VisitSel_class(sassy_parser.Sel_classContext context) - => new ClassSelector(context.GetCoordinate(), context.CLASS().GetText().TrimFirst()); - - /// - public override Node VisitSel_name(sassy_parser.Sel_nameContext context) - => new NameSelector(context.GetCoordinate(), context.NAME().GetText().TrimFirst()); - - /// - public override Node VisitSel_string_name(sassy_parser.Sel_string_nameContext context) => - new NameSelector(context.GetCoordinate(), context.STRING_NAME().GetText().TrimFirst().Unescape()); - - /// - public override Node VisitSel_intersection(sassy_parser.Sel_intersectionContext context) - => new IntersectionSelector(context.GetCoordinate(), Visit(context.lhs) as Selector, - Visit(context.rhs) as Selector); - - /// - public override Node VisitSel_ensure(sassy_parser.Sel_ensureContext context) => - new EnsureSelector(context.GetCoordinate(), context.ENSURE().GetText().TrimFirst()); - - /// - public override Node VisitSel_string_ensure(sassy_parser.Sel_string_ensureContext context) => - new EnsureSelector(context.GetCoordinate(), context.STRING_ENSURE().GetText().TrimFirst().Unescape()); - - /// - public override Node VisitSel_everything(sassy_parser.Sel_everythingContext context) - => new WildcardSelector(context.GetCoordinate()); - - /// - public override Node VisitSel_without_class(sassy_parser.Sel_without_classContext context) - => new WithoutClassSelector(context.GetCoordinate(), context.CLASS().GetText().TrimFirst()); - - /// - public override Node VisitSel_without_string_class(sassy_parser.Sel_without_string_classContext context) => - new WithoutClassSelector(context.GetCoordinate(), context.STRING_CLASS().GetText().TrimFirst().Unescape()); - - /// - public override Node VisitSel_without_name(sassy_parser.Sel_without_nameContext context) - => new WithoutNameSelector(context.GetCoordinate(), context.NAME().GetText().TrimFirst()); - - /// - public override Node VisitSel_without_string_name(sassy_parser.Sel_without_string_nameContext context) - => new WithoutNameSelector(context.GetCoordinate(), context.STRING_NAME().GetText().TrimFirst().Unescape()); - - /// - public override Node VisitSel_combination(sassy_parser.Sel_combinationContext context) - => new CombinationSelector(context.GetCoordinate(), Visit(context.lhs) as Selector, - Visit(context.rhs) as Selector); - - /// - public override Node VisitRuleset_selector(sassy_parser.Ruleset_selectorContext context) - => new RulesetSelector(context.GetCoordinate(), context.RULESET().GetText().TrimFirst()); - - /// - public override Node VisitCombination_selector(sassy_parser.Combination_selectorContext context) - => new CombinationSelector(context.GetCoordinate(), Visit(context.lhs) as Selector, - Visit(context.rhs) as Selector); - - /// - public override Node VisitClass_capture_selector(sassy_parser.Class_capture_selectorContext context) => - new ClassCaptureSelector(context.GetCoordinate(), context.CLASS().GetText().TrimFirst(), - context.function_statement().Select(Visit).ToList()); - - /// - public override Node VisitString_class_capture_selector( - sassy_parser.String_class_capture_selectorContext context - ) => - new ClassCaptureSelector(context.GetCoordinate(), context.STRING_CLASS().GetText().TrimFirst().Unescape(), - context.function_statement().Select(Visit).ToList()); - - /// - public override Node VisitWithout_name(sassy_parser.Without_nameContext context) - => new WithoutNameSelector(context.GetCoordinate(), context.NAME().GetText().TrimFirst()); - - /// - public override Node VisitWithout_string_name(sassy_parser.Without_string_nameContext context) => - new WithoutNameSelector(context.GetCoordinate(), context.STRING_NAME().GetText().TrimFirst().Unescape()); - - /// - public override Node VisitClass_selector(sassy_parser.Class_selectorContext context) - => new ClassSelector(context.GetCoordinate(), context.CLASS().GetText().TrimFirst()); - - /// - public override Node VisitString_class_selector(sassy_parser.String_class_selectorContext context) => - new ClassSelector(context.GetCoordinate(), context.STRING_CLASS().GetText().TrimFirst().Unescape()); - - /// - public override Node VisitWithout_class(sassy_parser.Without_classContext context) - => new WithoutClassSelector(context.GetCoordinate(), context.CLASS().GetText().TrimFirst()); - - /// - public override Node VisitWithout_string_class(sassy_parser.Without_string_classContext context) => - new WithoutClassSelector(context.GetCoordinate(), context.STRING_CLASS().GetText().TrimFirst().Unescape()); - - /// - public override Node VisitName(sassy_parser.NameContext context) - => new NameSelector(context.GetCoordinate(), context.NAME().GetText().TrimFirst()); - - /// - public override Node VisitString_name(sassy_parser.String_nameContext context) - => new NameSelector(context.GetCoordinate(), context.STRING_NAME().GetText().TrimFirst().Unescape()); - - /// - public override Node VisitAdd_element(sassy_parser.Add_elementContext context) - => new ElementAdditionSelector(context.GetCoordinate(), context.ELEMENT().GetText()); - - /// - public override Node VisitAdd_string_element(sassy_parser.Add_string_elementContext context) - => new ElementAdditionSelector(context.GetCoordinate(), context.STRING().GetText().Unescape()); - - /// - public override Node VisitEverything(sassy_parser.EverythingContext context) - => new WildcardSelector(context.GetCoordinate()); - - /// - public override Node VisitIntersection_selector(sassy_parser.Intersection_selectorContext context) - => new IntersectionSelector(context.GetCoordinate(), Visit(context.lhs) as Selector, - Visit(context.rhs) as Selector); - - /// - public override Node VisitElement(sassy_parser.ElementContext context) - => new ElementSelector(context.GetCoordinate(), context.ELEMENT().GetText()); - - /// - public override Node VisitString_element(sassy_parser.String_elementContext context) => - new ElementSelector(context.GetCoordinate(), context.STRING().GetText().Unescape()); - - /// - public override Node VisitSel_level_conditional(sassy_parser.Sel_level_conditionalContext context) - { - Node @else = null; - if (context.els != null) - { - @else = Visit(context.els); - } - - return new Conditional(context.GetCoordinate(), - Visit(context.cond) as Expression, - context.selector_statement() - .Select(Visit) - .ToList(), - @else); - } - - /// - public override Node VisitSel_level_else_else(sassy_parser.Sel_level_else_elseContext context) => - new Block(context.GetCoordinate(), - context.selector_statement() - .Select(Visit) - .ToList()); - - /// - public override Node VisitSel_level_else_if(sassy_parser.Sel_level_else_ifContext context) - { - Node @else = null; - if (context.els != null) - { - @else = Visit(context.els); - } - - return new Conditional(context.GetCoordinate(), - Visit(context.cond) as Expression, - context.selector_statement() - .Select(Visit) - .ToList(), - @else); - } - - /// - public override Node VisitSet_value(sassy_parser.Set_valueContext context) - => new SetValue(context.GetCoordinate(), Visit(context.expr) as Expression); - - /// - public override Node VisitDelete_value(sassy_parser.Delete_valueContext context) - => new DeleteValue(context.GetCoordinate()); - - /// - public override Node VisitMerge_value(sassy_parser.Merge_valueContext context) - => new MergeValue(context.GetCoordinate(), Visit(context.expr) as Expression); - - /// - public override Node VisitNormal_field_set(sassy_parser.Normal_field_setContext context) => - new Field(context.GetCoordinate(), - context.sassy_string().GetStringValue(), - context.index().Select(Visit).Cast().ToList(), - Visit(context.expr) as Expression); - - /// - public override Node VisitAdd_field_set(sassy_parser.Add_field_setContext context) => - new Field(context.GetCoordinate(), - context.sassy_string().GetStringValue(), - context.index().Select(Visit).Cast().ToList(), - new ImplicitAdd(context.GetCoordinate(), Visit(context.expr) as Expression)); - - /// - public override Node VisitSubtract_field_set(sassy_parser.Subtract_field_setContext context) => - new Field(context.GetCoordinate(), - context.sassy_string().GetStringValue(), - context.index().Select(Visit).Cast().ToList(), - new ImplicitSubtract(context.GetCoordinate(), Visit(context.expr) as Expression)); - - /// - public override Node VisitMultiply_field_set(sassy_parser.Multiply_field_setContext context) => - new Field(context.GetCoordinate(), - context.sassy_string().GetStringValue(), - context.index().Select(Visit).Cast().ToList(), - new ImplicitMultiply(context.GetCoordinate(), Visit(context.expr) as Expression)); - - - /// - public override Node VisitDivide_field_set(sassy_parser.Divide_field_setContext context) => - new Field(context.GetCoordinate(), - context.sassy_string().GetStringValue(), - context.index().Select(Visit).Cast().ToList(), - new ImplicitDivide(context.GetCoordinate(), Visit(context.expr) as Expression)); - - - public override Node VisitExpression_indexer(sassy_parser.Expression_indexerContext context) => new SingleIndexer(context.GetCoordinate(),Visit(context.expression()) as Expression); - - public override Node VisitMap_indexer(sassy_parser.Map_indexerContext context) => new EverythingIndexer(context.GetCoordinate()); - - - /// - public override Node VisitNot_equal_to(sassy_parser.Not_equal_toContext context) => - new NotEqualTo(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); - - /// - public override Node VisitVariable_reference(sassy_parser.Variable_referenceContext context) => - new VariableReference(context.GetCoordinate(), context.VARIABLE().GetText().TrimFirst()); - - /// - public override Node VisitEqual_to(sassy_parser.Equal_toContext context) => - new EqualTo(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); - - /// - public override Node VisitLocal_variable_reference(sassy_parser.Local_variable_referenceContext context) => - new LocalVariableReference(context.GetCoordinate(), context.LOCALVARIABLE().GetText().TrimFirst().TrimFirst()); - - - /// - public override Node VisitIndexor(sassy_parser.IndexorContext context) => - new Subscript(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); - - /// - public override Node VisitOr(sassy_parser.OrContext context) => - new Or(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); - - /// - public override Node VisitLesser_than_equal(sassy_parser.Lesser_than_equalContext context) => - new LesserThanEqual(context.GetCoordinate(), Visit(context.lhs) as Expression, - Visit(context.rhs) as Expression); - - /// - public override Node VisitSubtraction(sassy_parser.SubtractionContext context) => - new Subtract(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); - - /// - public override Node VisitPositive(sassy_parser.PositiveContext context) => - new Positive(context.GetCoordinate(), Visit(context.child) as Expression); - - /// - public override Node VisitSimple_call(sassy_parser.Simple_callContext context) => - new SimpleCall(context.GetCoordinate(), context.lhs.Text, - context.args.argument().Select(Visit).Cast().ToList()); - - /// - public override Node VisitDivision(sassy_parser.DivisionContext context) => - new Divide(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); - - /// - public override Node VisitNegative(sassy_parser.NegativeContext context) => - new Negate(context.GetCoordinate(), Visit(context.child) as Expression); - - /// - public override Node VisitNot(sassy_parser.NotContext context) => - new Not(context.GetCoordinate(), Visit(context.child) as Expression); - - /// - public override Node VisitLesser_than(sassy_parser.Lesser_thanContext context) => - new LesserThan(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); - - /// - public override Node VisitMember_call(sassy_parser.Member_callContext context) => - new MemberCall(context.GetCoordinate(), Visit(context.lhs) as Expression, context.name.Text, - context.args.argument().Select(Visit).Cast().ToList()); - - /// - public override Node VisitMember_call_ruleset(sassy_parser.Member_call_rulesetContext context) => - new MemberCall(context.GetCoordinate(), Visit(context.lhs) as Expression, - context.RULESET().GetText().TrimFirst(), - context.args.argument().Select(Visit).Cast().ToList()); - - /// - public override Node VisitGreater_than(sassy_parser.Greater_thanContext context) => - new GreaterThan(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); - - /// - public override Node VisitAnd(sassy_parser.AndContext context) => - new And(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); - - /// - public override Node VisitMultiplication(sassy_parser.MultiplicationContext context) => - new Multiply(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); - - /// - public override Node VisitRemainder(sassy_parser.RemainderContext context) => - new Remainder(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); - - /// - public override Node VisitGreater_than_equal(sassy_parser.Greater_than_equalContext context) => - new GreaterThanEqual(context.GetCoordinate(), Visit(context.lhs) as Expression, - Visit(context.rhs) as Expression); - - /// - public override Node VisitTernary(sassy_parser.TernaryContext context) => - new Ternary(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.cond) as Expression, - Visit(context.rhs) as Expression); - - /// - public override Node VisitAddition(sassy_parser.AdditionContext context) => - new Add(context.GetCoordinate(), Visit(context.lhs) as Expression, Visit(context.rhs) as Expression); - - /// - public override Node VisitValue_deletion(sassy_parser.Value_deletionContext context) - => new ValueNode(context.GetCoordinate(), new DataValue(DataValue.DataType.Deletion)); - - /// - public override Node VisitBoolean_true(sassy_parser.Boolean_trueContext context) - => new ValueNode(context.GetCoordinate(), true); - - /// - public override Node VisitBoolean_false(sassy_parser.Boolean_falseContext context) - => new ValueNode(context.GetCoordinate(), false); - - /// - public override Node VisitNumber_value(sassy_parser.Number_valueContext context) - { - var location = context.GetCoordinate(); - if (long.TryParse(context.NUMBER().GetText(), NumberStyles.Integer, CultureInfo.InvariantCulture, out var lng)) - { - return new ValueNode(location, lng); - } - - if (double.TryParse(context.NUMBER().GetText(), NumberStyles.Number, CultureInfo.InvariantCulture, out var dbl)) - { - return new ValueNode(location, dbl); - } - - Debug.Log($"Number: {context.NUMBER().GetText()}"); - return Error(location, "Numbers must be parsable as a double precision floating point number"); - } - - /// - public override Node VisitString_value(sassy_parser.String_valueContext context) - => new ValueNode(context.GetCoordinate(), context.STRING().GetText().Unescape()); - - /// - public override Node VisitNone(sassy_parser.NoneContext context) - => new ValueNode(context.GetCoordinate(), new DataValue(DataValue.DataType.None)); - - /// - public override Node VisitList_value(sassy_parser.List_valueContext context) - => new ListNode(context.GetCoordinate(), - context.list().list_values().expression().Select(Visit).Cast().ToList()); - - /// - public override Node VisitObject_value(sassy_parser.Object_valueContext context) - => new ObjectNode(context.GetCoordinate(), - context.obj().obj_values().key_value().Select(Visit).Cast().ToList()); - - /// - public override Node VisitLiteral_key(sassy_parser.Literal_keyContext context) - => new KeyValueNode(context.GetCoordinate(), context.key.Text, Visit(context.val) as Expression); - - /// - public override Node VisitString_key(sassy_parser.String_keyContext context) - => new KeyValueNode(context.GetCoordinate(), context.key.Text.Unescape(), Visit(context.val) as Expression); - - /// - public override Node VisitNamed_argument(sassy_parser.Named_argumentContext context) - => new CallArgument(context.GetCoordinate(), context.key.Text.TrimFirst(), Visit(context.val) as Expression); - - /// - public override Node VisitUnnamed_argument(sassy_parser.Unnamed_argumentContext context) - => new CallArgument(context.GetCoordinate(), Visit(context.val) as Expression); - - /// - public override Node VisitFn_level_conditional(sassy_parser.Fn_level_conditionalContext context) - { - Node @else = null; - if (context.els != null) - { - @else = Visit(context.els); - } - - return new Conditional(context.GetCoordinate(), - Visit(context.cond) as Expression, - context.function_statement() - .Select(Visit) - .ToList(), - @else); - } - - /// - public override Node VisitFn_level_else_else(sassy_parser.Fn_level_else_elseContext context) => - new Block(context.GetCoordinate(), - context.function_statement() - .Select(Visit) - .ToList()); - - /// - public override Node VisitFn_level_else_if(sassy_parser.Fn_level_else_ifContext context) - { - Node @else = null; - if (context.els != null) - { - @else = Visit(context.els); - } - - return new Conditional(context.GetCoordinate(), - Visit(context.cond) as Expression, - context.function_statement() - .Select(Visit) - .ToList(), - @else); - } - - /// - public override Node VisitFn_return(sassy_parser.Fn_returnContext context) - { - return new Return(context.GetCoordinate(), Visit(context.expression()) as Expression); - } - - /// - public override Node VisitMixin_include(sassy_parser.Mixin_includeContext context) => - new MixinInclude(context.GetCoordinate(), context.mixin.Text, - context.args.argument().Select(Visit).Cast().ToList()); - - - /// - public override Node VisitMixin_block_include(sassy_parser.Mixin_block_includeContext context) => - new MixinBlockInclude(context.GetCoordinate(), context.mixin.Text, - context.args.argument().Select(Visit).Cast().ToList(), - context.selector_statement().Select(Visit).ToList()); - - public override Node VisitMixin_slot(sassy_parser.Mixin_slotContext context) => - new MixinSlot(context.GetCoordinate()); - - /// - public override Node VisitArgument_without_default(sassy_parser.Argument_without_defaultContext context) - => new Argument(context.GetCoordinate(), context.name.Text.TrimFirst()); - - /// - public override Node VisitArgument_with_default(sassy_parser.Argument_with_defaultContext context) - => new Argument(context.GetCoordinate(), context.name.Text.TrimFirst(), Visit(context.val) as Expression); - - /// - public override Node VisitSel_sub(sassy_parser.Sel_subContext context) => - Visit(context.internal_selector); - - /// - public override Node VisitSub_selector(sassy_parser.Sub_selectorContext context) => - Visit(context.internal_selector); - - /// - public override Node VisitSub_sub_expression(sassy_parser.Sub_sub_expressionContext context) => - Visit(context.internal_expr); - - /// - public override Node VisitFor_to_loop(sassy_parser.For_to_loopContext context) - => new For(context.GetCoordinate(), context.idx.Text.TrimFirst(), Visit(context.for_start) as Expression, false, - Visit(context.end) as Expression, context.function_statement().Select(Visit).ToList()); - - /// - public override Node VisitTop_level_for_to_loop(sassy_parser.Top_level_for_to_loopContext context) => new For( - context.GetCoordinate(), context.idx.Text.TrimFirst(), Visit(context.for_start) as Expression, false, - Visit(context.end) as Expression, context.top_level_statement().Select(Visit).ToList()); - - /// - public override Node VisitSel_level_for_to_loop(sassy_parser.Sel_level_for_to_loopContext context) => new For( - context.GetCoordinate(), context.idx.Text.TrimFirst(), Visit(context.for_start) as Expression, false, - Visit(context.end) as Expression, context.selector_statement().Select(Visit).ToList()); - - /// - public override Node VisitFor_through_loop(sassy_parser.For_through_loopContext context) - => new For(context.GetCoordinate(), context.idx.Text.TrimFirst(), Visit(context.for_start) as Expression, true, - Visit(context.end) as Expression, context.function_statement().Select(Visit).ToList()); - - - /// - public override Node VisitTop_level_for_through_loop(sassy_parser.Top_level_for_through_loopContext context) - => new For(context.GetCoordinate(), context.idx.Text.TrimFirst(), Visit(context.for_start) as Expression, true, - Visit(context.end) as Expression, context.top_level_statement().Select(Visit).ToList()); - - /// - public override Node VisitSel_level_for_through_loop(sassy_parser.Sel_level_for_through_loopContext context) - => new For(context.GetCoordinate(), context.idx.Text.TrimFirst(), Visit(context.for_start) as Expression, true, - Visit(context.end) as Expression, context.selector_statement().Select(Visit).ToList()); - - /// - public override Node VisitEach_loop(sassy_parser.Each_loopContext context) - => new Each(context.GetCoordinate(), context.key?.Text.TrimFirst(), context.val.Text.TrimFirst(), - Visit(context.iter) as Expression, context.function_statement().Select(Visit).ToList()); - - /// - public override Node VisitTop_level_each_loop(sassy_parser.Top_level_each_loopContext context) - => new Each(context.GetCoordinate(), context.key?.Text.TrimFirst(), context.val.Text.TrimFirst(), - Visit(context.iter) as Expression, context.top_level_statement().Select(Visit).ToList()); - - /// - public override Node VisitSel_level_each_loop(sassy_parser.Sel_level_each_loopContext context) - => new Each(context.GetCoordinate(), context.key?.Text.TrimFirst(), context.val.Text.TrimFirst(), - Visit(context.iter) as Expression, context.selector_statement().Select(Visit).ToList()); - - /// - public override Node VisitWhile_loop(sassy_parser.While_loopContext context) - => new While(context.GetCoordinate(), Visit(context.cond) as Expression, - context.function_statement().Select(Visit).ToList()); - - /// - public override Node VisitTop_level_while_loop(sassy_parser.Top_level_while_loopContext context) - => new While(context.GetCoordinate(), Visit(context.cond) as Expression, - context.top_level_statement().Select(Visit).ToList()); - - /// - public override Node VisitSel_level_while_loop(sassy_parser.Sel_level_while_loopContext context) - => new While(context.GetCoordinate(), Visit(context.cond) as Expression, - context.selector_statement().Select(Visit).ToList()); - - /// - public override Node VisitGlobal_stage_def(sassy_parser.Global_stage_defContext context) => - new StageDefinition(context.GetCoordinate(), context.stage.GetStringValue(), true); - - /// - public override Node VisitImplicit_stage_def(sassy_parser.Implicit_stage_defContext context) => - new StageDefinition(context.GetCoordinate(), context.stage.GetStringValue()); - - /// - public override Node VisitRelative_stage_def(sassy_parser.Relative_stage_defContext context) => new StageDefinition( - context.GetCoordinate(), context.stage.GetStringValue(), - context.stage_attribute().Select(Visit).Cast().ToList()); - - public override Node VisitStage_value_before(sassy_parser.Stage_value_beforeContext context) => - new StageDefinitionAttribute(context.GetCoordinate(), context.stage.GetStringValue(), false); - - public override Node VisitStage_value_after(sassy_parser.Stage_value_afterContext context) => - new StageDefinitionAttribute(context.GetCoordinate(), context.stage.GetStringValue(), true); - - /// - public override Node VisitConfig_creation(sassy_parser.Config_creationContext context) => new ConfigCreation( - context.GetCoordinate(), context.label.GetStringValue(), context.config_name.GetStringValue(), - Visit(context.config_value) as Expression); - - /// - public override Node VisitElement_string(sassy_parser.Element_stringContext context) => - new ValueNode(context.GetCoordinate(), context.ELEMENT().GetText()); - - /// - public override Node VisitUpdate_config_full(sassy_parser.Update_config_fullContext context) => new ConfigUpdate( - context.GetCoordinate(), Visit(context.priority) as Expression, context.label.GetStringValue(), - context.config_name.GetStringValue(), Visit(context.config_update) as Expression); - - /// - public override Node VisitUpdate_config_label(sassy_parser.Update_config_labelContext context) => new ConfigUpdate( - context.GetCoordinate(), Visit(context.priority) as Expression, context.label.GetStringValue(), null, - Visit(context.config_update) as Expression); - -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Utility/Extensions.cs b/src/PatchManager.SassyPatching/Utility/Extensions.cs deleted file mode 100644 index a848c7c..0000000 --- a/src/PatchManager.SassyPatching/Utility/Extensions.cs +++ /dev/null @@ -1,129 +0,0 @@ -using System.Text; -using System.Text.RegularExpressions; -using Antlr4.Runtime; -using Newtonsoft.Json; -using PatchManager.SassyPatching.Execution; -using PatchManager.SassyPatching.Nodes.Expressions; -using SassyPatchGrammar; -using UnityEngine; -using Environment = PatchManager.SassyPatching.Execution.Environment; - -namespace PatchManager.SassyPatching.Utility; - -internal static class Extensions -{ - public static string Unescape(this string @this) => Regex.Unescape(@this.Substring(1, @this.Length - 2)); - - public static string TrimFirst(this string @this) => @this.Substring(1); - - public static Coordinate GetCoordinate(this ParserRuleContext @this) => - new(@this.Start.TokenSource.SourceName, @this.Start.Line, @this.Start.Column); - - public static bool MatchesPattern(this string @this, string pattern) => - Regex.IsMatch(@this, $"^{pattern.Replace("*", ".*").Replace("?", ".?")}$"); - - public static string Escape(this string @this) => JsonConvert.ToString(@this); - - public static string GetStringValue(this sassy_parser.Sassy_stringContext ctx) - { - if (ctx is sassy_parser.Quoted_stringContext quotedStringContext) - { - return quotedStringContext.STRING().GetText().Unescape(); - } - - var unquotedStringContext = ctx as sassy_parser.Unquoted_stringContext; - return unquotedStringContext!.ELEMENT().GetText(); - } - - private static object GetResult(this string variable, Environment environment) - { - var lexer = new sassy_lexer(CharStreams.fromString(variable)); - var lexerErrorGenerator = new Universe.LexerListener("Interpolated string", - environment.GlobalEnvironment.Universe.MessageLogger); - lexer.AddErrorListener(lexerErrorGenerator); - if (lexerErrorGenerator.Errored) - { - throw new Exception("Lexer errors detected"); - } - - var tokenStream = new CommonTokenStream(lexer); - var parser = new sassy_parser(tokenStream); - var parserErrorGenerator = new Universe.ParserListener("Interpolated string", - environment.GlobalEnvironment.Universe.MessageLogger); - parser.AddErrorListener(parserErrorGenerator); - var expressionContext = parser.expression(); - if (parserErrorGenerator.Errored) - throw new Exception("parser errors detected"); - var tokenTransformer = new Transformer(msg => throw new Exception(msg)); - var ctx = tokenTransformer.Visit(expressionContext) as Expression; - var result = ctx!.Compute(environment); - return result.IsString ? result.String : result.ToString(); - } - - public static string Interpolate(this string toBeInterpolated, Environment environment) - { - if (toBeInterpolated.IndexOf("#", StringComparison.Ordinal) == -1) - return toBeInterpolated; - StringBuilder format = new(); - var inFormat = false; - var currentString = ""; - var lookForStart = false; - - foreach (var character in toBeInterpolated) - { - if (inFormat) - { - if (character is '}') - { - format.Append(currentString.GetResult(environment)); - inFormat = false; - } - else - { - currentString += character; - } - } - else - { - if (lookForStart) - { - switch (character) - { - case '{': - currentString = ""; - inFormat = true; - break; - case '#': - format.Append('#'); - break; - default: - format.Append('#'); - format.Append(character); - break; - } - - lookForStart = false; - } - else if (character == '#') - { - lookForStart = true; - } - else - { - format.Append(character); - } - } - } - - if (lookForStart) - { - format.Append('#'); - } - - if (inFormat) - { - throw new Exception("Unterminated interpolated string"); - } - return format.ToString(); - } -} \ No newline at end of file diff --git a/src/PatchManager.SassyPatching/Utility/GlobalUsings.cs b/src/PatchManager.SassyPatching/Utility/GlobalUsings.cs deleted file mode 100644 index 8208064..0000000 --- a/src/PatchManager.SassyPatching/Utility/GlobalUsings.cs +++ /dev/null @@ -1 +0,0 @@ -global using static PatchManager.SassyPatching.Utility.Extensions; \ No newline at end of file diff --git a/src/PatchManager.Science/Modifiables/DiscoverablesModifiable.cs b/src/PatchManager.Science/Modifiables/DiscoverablesModifiable.cs deleted file mode 100644 index dba6efd..0000000 --- a/src/PatchManager.Science/Modifiables/DiscoverablesModifiable.cs +++ /dev/null @@ -1,32 +0,0 @@ -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Modifiables; -using PatchManager.Science.Selectables; - -namespace PatchManager.Science.Modifiables; -/// -/// Modifiable for . This is used to modify the discoverables object. -/// -public class DiscoverablesModifiable : JTokenModifiable -{ - private DiscoverablesSelectable _discoverablesSelectable; - - /// - /// Creates a new for the given . - /// - /// The selectable to modify. - public DiscoverablesModifiable(DiscoverablesSelectable selectable) : base(selectable.DiscoverablesObject, selectable.SetModified) - { - _discoverablesSelectable = selectable; - } - - /// - public override void Set(DataValue dataValue) - { - if (dataValue.IsDeletion) - { - _discoverablesSelectable.SetDeleted(); - return; - } - base.Set(dataValue); - } -} \ No newline at end of file diff --git a/src/PatchManager.Science/Modifiables/ExperimentModifiable.cs b/src/PatchManager.Science/Modifiables/ExperimentModifiable.cs deleted file mode 100644 index d82c6fd..0000000 --- a/src/PatchManager.Science/Modifiables/ExperimentModifiable.cs +++ /dev/null @@ -1,36 +0,0 @@ -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Modifiables; -using PatchManager.Science.Selectables; - -namespace PatchManager.Science.Modifiables; - -/// -/// Modifiable for . -/// -public class ExperimentModifiable : JTokenModifiable -{ - /// - /// The this modifiable is for. - /// - private ExperimentSelectable _experimentSelectable; - - /// - /// Creates a new for the given . - /// - /// The this modifiable is for. - public ExperimentModifiable(ExperimentSelectable selectable) : base(selectable.DataObject, selectable.SetModified) - { - _experimentSelectable = selectable; - } - - /// - public override void Set(DataValue dataValue) - { - if (dataValue.IsDeletion) - { - _experimentSelectable.SetDeleted(); - return; - } - base.Set(dataValue); - } -} \ No newline at end of file diff --git a/src/PatchManager.Science/Modifiables/RegionsModifiable.cs b/src/PatchManager.Science/Modifiables/RegionsModifiable.cs deleted file mode 100644 index 6a45bd6..0000000 --- a/src/PatchManager.Science/Modifiables/RegionsModifiable.cs +++ /dev/null @@ -1,33 +0,0 @@ -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Modifiables; -using PatchManager.Science.Selectables; - -namespace PatchManager.Science.Modifiables; - -/// -/// Modifiable for . This is used to modify the discoverables object. -/// -public class RegionsModifiable : JTokenModifiable -{ - private RegionsSelectable _regionsSelectable; - - /// - /// Creates a new for the given . - /// - /// The selectable to modify. - public RegionsModifiable(RegionsSelectable selectable) : base(selectable.RegionsObject, selectable.SetModified) - { - _regionsSelectable = selectable; - } - - /// - public override void Set(DataValue dataValue) - { - if (dataValue.IsDeletion) - { - _regionsSelectable.SetDeleted(); - return; - } - base.Set(dataValue); - } -} \ No newline at end of file diff --git a/src/PatchManager.Science/Modifiables/ScienceModifiable.cs b/src/PatchManager.Science/Modifiables/ScienceModifiable.cs deleted file mode 100644 index 771ad08..0000000 --- a/src/PatchManager.Science/Modifiables/ScienceModifiable.cs +++ /dev/null @@ -1,33 +0,0 @@ -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Modifiables; -using PatchManager.Science.Selectables; - -namespace PatchManager.Science.Modifiables; - -/// -/// Modifiable for . This is used to modify the science object. -/// -public class ScienceModifiable : JTokenModifiable -{ - private ScienceSelectable _scienceSelectable; - - /// - /// Creates a new for the given . - /// - /// The selectable to modify. - public ScienceModifiable(ScienceSelectable selectable) : base(selectable.ScienceObject, selectable.SetModified) - { - _scienceSelectable = selectable; - } - - /// - public override void Set(DataValue dataValue) - { - if (dataValue.IsDeletion) - { - _scienceSelectable.SetDeleted(); - return; - } - base.Set(dataValue); - } -} \ No newline at end of file diff --git a/src/PatchManager.Science/PatchManager.Science.csproj b/src/PatchManager.Science/PatchManager.Science.csproj deleted file mode 100644 index 1a01286..0000000 --- a/src/PatchManager.Science/PatchManager.Science.csproj +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/PatchManager.Science/Rulesets/DiscoverablesRuleset.cs b/src/PatchManager.Science/Rulesets/DiscoverablesRuleset.cs deleted file mode 100644 index cbb5dd2..0000000 --- a/src/PatchManager.Science/Rulesets/DiscoverablesRuleset.cs +++ /dev/null @@ -1,38 +0,0 @@ -using KSP.Game.Science; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.NewAssets; -using PatchManager.Science.Selectables; - -namespace PatchManager.Science.Rulesets; - -/// -/// A ruleset for modifying discoverable positions in the game -/// -[PatcherRuleset("discoverables","science_region_discoverables")] -public class DiscoverablesRuleset : IPatcherRuleSet -{ - /// - public bool Matches(string label) => label == "science_region_discoverables"; - - /// - public ISelectable ConvertToSelectable(string type, string name, string jsonData) => - new DiscoverablesSelectable(JObject.Parse(jsonData)); - - /// - public INewAsset CreateNew(List dataValues) - { - var bodyName = dataValues[0].String; - var bakedDiscoverables = new CelestialBodyBakedDiscoverables - { - BodyName = bodyName, - Discoverables = [], - Version = dataValues.Count > 1 ? dataValues[1].String : "0.1" - }; - return new NewGenericAsset("science_region_discoverables", - $"{bodyName.ToLowerInvariant()}_science_regions_discoverables", - new DiscoverablesSelectable(JObject.FromObject(bakedDiscoverables))); - } -} \ No newline at end of file diff --git a/src/PatchManager.Science/Rulesets/ExperimentRuleset.cs b/src/PatchManager.Science/Rulesets/ExperimentRuleset.cs deleted file mode 100644 index 155b6db..0000000 --- a/src/PatchManager.Science/Rulesets/ExperimentRuleset.cs +++ /dev/null @@ -1,38 +0,0 @@ -using JetBrains.Annotations; -using KSP.Game.Science; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.NewAssets; -using PatchManager.Science.Selectables; - -namespace PatchManager.Science.Rulesets; - -/// -/// Ruleset for the ScienceExperiment part module. -/// -[PatcherRuleset("experiments","scienceExperiment"),UsedImplicitly] -public class ExperimentRuleset : IPatcherRuleSet -{ - /// - public bool Matches(string label) => label == "scienceExperiment"; - - /// - public ISelectable ConvertToSelectable(string type, string name, string jsonData) => - new ExperimentSelectable(JObject.Parse(jsonData)); - - /// - public INewAsset CreateNew(List dataValues) - { - var core = new ExperimentCore - { - data = new ExperimentDefinition - { - ExperimentID = dataValues[0].String - } - }; - return new NewGenericAsset("scienceExperiment", dataValues[0].String, - new ExperimentSelectable(JObject.FromObject(core))); - } -} \ No newline at end of file diff --git a/src/PatchManager.Science/Rulesets/RegionsRuleset.cs b/src/PatchManager.Science/Rulesets/RegionsRuleset.cs deleted file mode 100644 index 833bbed..0000000 --- a/src/PatchManager.Science/Rulesets/RegionsRuleset.cs +++ /dev/null @@ -1,38 +0,0 @@ -using KSP.Game.Science; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.NewAssets; -using PatchManager.Science.Selectables; - -namespace PatchManager.Science.Rulesets; -/// -/// Ruleset for science regions -/// -[PatcherRuleset("regions","science_region")] -public class RegionsRuleset : IPatcherRuleSet -{ - /// - public bool Matches(string label) => label == "science_region"; - - /// - public ISelectable ConvertToSelectable(string type, string name, string jsonData) => - new RegionsSelectable(JObject.Parse(jsonData)); - - /// - public INewAsset CreateNew(List dataValues) - { - var bodyName = dataValues[0].String; - var bakedDiscoverables = new CelestialBodyScienceRegionsData - { - BodyName = bodyName, - SituationData = new CBSituationData(), - Regions = [], - Version = dataValues.Count > 1 ? dataValues[1].String : "0.1" - }; - return new NewGenericAsset("science_region", - $"{bodyName.ToLowerInvariant()}_science_regions", - new RegionsSelectable(JObject.FromObject(bakedDiscoverables))); - } -} \ No newline at end of file diff --git a/src/PatchManager.Science/Rulesets/ScienceRuleset.cs b/src/PatchManager.Science/Rulesets/ScienceRuleset.cs deleted file mode 100644 index 9127b69..0000000 --- a/src/PatchManager.Science/Rulesets/ScienceRuleset.cs +++ /dev/null @@ -1,29 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Attributes; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.NewAssets; -using PatchManager.Science.Selectables; - -namespace PatchManager.Science.Rulesets; - -/// -/// This ruleset is used to patch the science tech tree. -/// -[PatcherRuleset("science","techNodeData")] -public class ScienceRuleset : IPatcherRuleSet -{ - /// - public bool Matches(string label) => label == "techNodeData"; - - /// - public ISelectable ConvertToSelectable(string type, string name, string jsonData) => - new ScienceSelectable(JObject.Parse(jsonData)); - - /// - public INewAsset CreateNew(List dataValues) - { - return new NewGenericAsset("techNodeData", dataValues[0].String, - new ScienceSelectable(JObject.Parse($"{{\n \"Version\": 12,\n \"ID\": \"{dataValues[0].String}\",\n \"NameLocKey\": \"Science/TechNodes/Names/tNode_4v_docking_01\",\n \"IconID\": \"ICO-RDCenter-Docking-24x\",\n \"CategoryID\": \"\",\n \"HiddenByNodeID\": \"\",\n \"DescriptionLocKey\": \"Science/TechNodes/Descriptions/tNode_4v_docking_01\",\n \"RequiredSciencePoints\": 7000,\n \"UnlockedPartsIDs\": [\n \"dockingring_4v_inline\",\n \"dockingport_3v_inline\"\n ],\n \"RequiredTechNodeIDs\": [\n \"tNode_4v_decouplers_01\"\n ],\n \"TierToUnlock\": 0,\n \"TechTreePosition\": {{\n \"x\": 5220.0,\n \"y\": 310.0\n }}\n}}"))); - } -} \ No newline at end of file diff --git a/src/PatchManager.Science/ScienceModule.cs b/src/PatchManager.Science/ScienceModule.cs deleted file mode 100644 index fc8da15..0000000 --- a/src/PatchManager.Science/ScienceModule.cs +++ /dev/null @@ -1,12 +0,0 @@ -using JetBrains.Annotations; -using PatchManager.Shared.Modules; - -namespace PatchManager.Science; - -/// -/// The science module. -/// -[UsedImplicitly] -public class ScienceModule : BaseModule -{ -} \ No newline at end of file diff --git a/src/PatchManager.Science/Selectables/DiscoverablesSelectable.cs b/src/PatchManager.Science/Selectables/DiscoverablesSelectable.cs deleted file mode 100644 index d285aca..0000000 --- a/src/PatchManager.Science/Selectables/DiscoverablesSelectable.cs +++ /dev/null @@ -1,125 +0,0 @@ -using KSP.Game.Science; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Selectables; -using PatchManager.Science.Modifiables; - -namespace PatchManager.Science.Selectables; - -/// -/// A selectable that represents discoverables -/// -public sealed class DiscoverablesSelectable : BaseSelectable -{ -#pragma warning disable CS0414 // Field is assigned but its value is never used - private bool _modified; -#pragma warning restore CS0414 // Field is assigned but its value is never used - private bool _deleted; - - /// - /// Marks this part selectable as having been modified any level down - /// - public void SetModified() - { - _modified = true; - } - - /// - /// Marks this part as goneso - /// - public void SetDeleted() - { - SetModified(); - _deleted = true; - } - - - /// - /// The main object that represents this discoverable object - /// - public JObject DiscoverablesObject; - private JArray _discoverablesArray; - - /// - /// Create a new discoverables selectable from a JObject - /// - /// Discoverable - public DiscoverablesSelectable(JObject discoverablesObject) - { - DiscoverablesObject = discoverablesObject; - ElementType = "discoverables"; - Name = discoverablesObject["BodyName"].Value(); - Children = []; - Classes = - ["BodyName"]; - _discoverablesArray = (JArray)discoverablesObject["Discoverables"]; - foreach (var jToken in _discoverablesArray) - { - var discoverable = (JObject)jToken; - var name = discoverable["ScienceRegionId"]!.Value(); - Classes.Add(name); - Children.Add(new JTokenSelectable(SetModified, discoverable, - disc => ((JObject)disc)["ScienceRegionId"]!.Value(), "discoverable")); - } - } - - /// - public override List Children { get; } - - /// - public override string Name { get; } - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - foreach (var jToken in _discoverablesArray) - { - var discoverable = (JObject)jToken; - var name = discoverable["ScienceRegionId"]!.Value(); - if (name != @class) continue; - classValue = DataValue.FromJToken(discoverable); - return true; - } - classValue = DataValue.Null; - return false; - } - - /// - public override bool IsSameAs(ISelectable other) => other is DiscoverablesSelectable discoverablesSelectable && - discoverablesSelectable.DiscoverablesObject == - DiscoverablesObject; - - /// - public override IModifiable OpenModification() => new DiscoverablesModifiable(this); - - /// - public override ISelectable AddElement(string elementType) - { - var position = new CelestialBodyDiscoverablePosition - { - ScienceRegionId = elementType, - Position = new Vector3d(), - Radius = 0.0 - }; - var jObject = JObject.FromObject(position); - _discoverablesArray.Add(jObject); - var selectable = new JTokenSelectable(SetModified, jObject, - disc => ((JObject)disc)["ScienceRegionId"]!.Value(), "discoverable"); - Classes.Add(elementType); - Children.Add(selectable); - return selectable; - } - - /// - public override string Serialize() => _deleted ? "" : DiscoverablesObject.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(DiscoverablesObject); - - /// - public override string ElementType { get; } -} \ No newline at end of file diff --git a/src/PatchManager.Science/Selectables/ExperimentSelectable.cs b/src/PatchManager.Science/Selectables/ExperimentSelectable.cs deleted file mode 100644 index 7d75a35..0000000 --- a/src/PatchManager.Science/Selectables/ExperimentSelectable.cs +++ /dev/null @@ -1,111 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Selectables; -using PatchManager.Science.Modifiables; - -namespace PatchManager.Science.Selectables; - -/// -/// A selectable that represents a science experiment -/// -public class ExperimentSelectable : BaseSelectable -{ -#pragma warning disable CS0414 // Field is assigned but its value is never used - private bool _modified; -#pragma warning restore CS0414 // Field is assigned but its value is never used - private bool _deleted; - - /// - /// Marks this part selectable as having been modified any level down - /// - public void SetModified() - { - _modified = true; - } - - /// - /// Marks this part as goneso - /// - public void SetDeleted() - { - SetModified(); - _deleted = true; - } - - /// - /// The science object that this selectable represents - /// - public JObject ScienceObject; - - /// - /// The data object that this selectable represents - /// - public JObject DataObject; - - /// - /// Creates a new experiment selectable - /// - /// The science data that this selectable represents - public ExperimentSelectable(JObject scienceData) - { - ElementType = "scienceExperiment"; - ScienceObject = scienceData; - DataObject = (JObject)scienceData["data"]!; - Classes = []; - Children = []; - foreach (var subToken in DataObject) - { - Classes.Add(subToken.Key); - Children.Add(new JTokenSelectable(SetModified,subToken.Value,subToken.Key)); - } - } - - /// - public sealed override List Children { get; } - - /// - public override string Name => DataObject["ExperimentID"]!.Value()!; - - /// - public sealed override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - classValue = null; - if (!MatchesClass(@class)) - { - return false; - } - - classValue = DataValue.FromJToken(DataObject[@class]); - return true; - } - - /// - public override string ElementType { get; } - - /// - public override bool IsSameAs(ISelectable other) => - other is ScienceSelectable selectable && selectable.ScienceObject == ScienceObject; - - /// - public override IModifiable OpenModification() => new ExperimentModifiable(this); - - /// - public override ISelectable AddElement(string elementType) - { - var obj = new JObject(); - DataObject[elementType] = obj; - var n = new JTokenSelectable(SetModified, obj, elementType); - Children.Add(n); - return n; - } - - /// - public override string Serialize() => _deleted ? "" : ScienceObject.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(DataObject); -} \ No newline at end of file diff --git a/src/PatchManager.Science/Selectables/RegionsSelectable.cs b/src/PatchManager.Science/Selectables/RegionsSelectable.cs deleted file mode 100644 index 94ca94f..0000000 --- a/src/PatchManager.Science/Selectables/RegionsSelectable.cs +++ /dev/null @@ -1,124 +0,0 @@ -using KSP.Game.Science; -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Selectables; -using PatchManager.Science.Modifiables; - -namespace PatchManager.Science.Selectables; - -/// -/// This is the selectable for science regions -/// -public sealed class RegionsSelectable : BaseSelectable -{ - #pragma warning disable CS0414 // Field is assigned but its value is never used - private bool _modified; -#pragma warning restore CS0414 // Field is assigned but its value is never used - private bool _deleted; - - /// - /// Marks this part selectable as having been modified any level down - /// - public void SetModified() - { - _modified = true; - } - - /// - /// Marks this part as goneso - /// - public void SetDeleted() - { - SetModified(); - _deleted = true; - } - - - /// - /// The main object that represents this discoverable object - /// - public JObject RegionsObject; - private JArray _regionsArray; - - /// - /// Create a new regions selectable from a JObject - /// - /// Region - public RegionsSelectable(JObject regionsObject) - { - RegionsObject = regionsObject; - ElementType = "regions"; - Name = regionsObject["BodyName"].Value(); - Children = [new JTokenSelectable(SetModified, regionsObject["SituationData"], "SituationData","SituationData")]; - Classes = ["BodyName", "SituationData"]; - _regionsArray = (JArray)regionsObject["Regions"]; - foreach (var jToken in _regionsArray) - { - var discoverable = (JObject)jToken; - var name = discoverable["Id"]!.Value(); - Classes.Add(name); - Children.Add(new JTokenSelectable(SetModified, discoverable, - disc => ((JObject)disc)["Id"]!.Value(), "region")); - } - } - - /// - public override List Children { get; } - - /// - public override string Name { get; } - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - foreach (var jToken in _regionsArray) - { - var discoverable = (JObject)jToken; - var name = discoverable["Id"]!.Value(); - if (name != @class) continue; - classValue = DataValue.FromJToken(discoverable); - return true; - } - classValue = DataValue.Null; - return false; - } - - /// - public override bool IsSameAs(ISelectable other) => other is RegionsSelectable regionsSelectable && - regionsSelectable.RegionsObject == - RegionsObject; - - /// - public override IModifiable OpenModification() => new RegionsModifiable(this); - - /// - public override ISelectable AddElement(string elementType) - { - var position = new CelestialBodyDiscoverablePosition - { - ScienceRegionId = elementType, - Position = new Vector3d(), - Radius = 0.0 - }; - var jObject = JObject.FromObject(position); - _regionsArray.Add(jObject); - var selectable = new JTokenSelectable(SetModified, jObject, - disc => ((JObject)disc)["ScienceRegionID"]!.Value(), "discoverable"); - Classes.Add(elementType); - Children.Add(selectable); - return selectable; - } - - /// - public override string Serialize() => _deleted ? "" : RegionsObject.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(RegionsObject); - - /// - public override string ElementType { get; } -} \ No newline at end of file diff --git a/src/PatchManager.Science/Selectables/ScienceSelectable.cs b/src/PatchManager.Science/Selectables/ScienceSelectable.cs deleted file mode 100644 index 7d481f8..0000000 --- a/src/PatchManager.Science/Selectables/ScienceSelectable.cs +++ /dev/null @@ -1,105 +0,0 @@ -using Newtonsoft.Json.Linq; -using PatchManager.SassyPatching; -using PatchManager.SassyPatching.Interfaces; -using PatchManager.SassyPatching.Selectables; -using PatchManager.Science.Modifiables; - -namespace PatchManager.Science.Selectables; - -/// -/// A selectable that represents a science experiment -/// -public sealed class ScienceSelectable : BaseSelectable -{ -#pragma warning disable CS0414 // Field is assigned but its value is never used - private bool _modified; -#pragma warning restore CS0414 // Field is assigned but its value is never used - private bool _deleted; - - /// - /// Marks this part selectable as having been modified any level down - /// - public void SetModified() - { - _modified = true; - } - - /// - /// Marks this part as goneso - /// - public void SetDeleted() - { - SetModified(); - _deleted = true; - } - - /// - /// The science object that this selectable represents - /// - public JObject ScienceObject; - - /// - /// Creates a new science selectable - /// - /// The science data that this selectable represents - public ScienceSelectable(JObject scienceData) - { - ElementType = "techNodeData"; - ScienceObject = scienceData; - Classes = new List(); - Children = new List(); - foreach (var subToken in ScienceObject) - { - Classes.Add(subToken.Key); - Children.Add(new JTokenSelectable(SetModified, subToken.Value, subToken.Key)); - } - } - - /// - public override List Children { get; } - - /// - public override string Name => ScienceObject["ID"]!.Value()!; - - /// - public override List Classes { get; } - - /// - public override bool MatchesClass(string @class, out DataValue classValue) - { - classValue = null; - if (!MatchesClass(@class)) - { - return false; - } - - classValue = DataValue.FromJToken(ScienceObject[@class]); - return true; - } - - /// - public override string ElementType { get; } - - /// - public override bool IsSameAs(ISelectable other) => - other is ScienceSelectable selectable && selectable.ScienceObject == ScienceObject; - - /// - public override IModifiable OpenModification() => new ScienceModifiable(this); - - /// - public override ISelectable AddElement(string elementType) - { - var obj = new JObject(); - ScienceObject[elementType] = obj; - var n = new JTokenSelectable(SetModified, obj, elementType); - Children.Add(n); - return n; - } - - /// - public override string Serialize() => _deleted ? "" : ScienceObject.ToString(); - - /// - public override DataValue GetValue() => DataValue.FromJToken(ScienceObject); -} \ No newline at end of file diff --git a/src/PatchManager.Shared/Extensions.cs b/src/PatchManager.Shared/Extensions.cs deleted file mode 100644 index 0354af1..0000000 --- a/src/PatchManager.Shared/Extensions.cs +++ /dev/null @@ -1,128 +0,0 @@ -namespace PatchManager.Shared; - -/// -/// Utility extension methods for various types. -/// -public static class Extensions -{ - /// - /// Deconstructs a into its key and value. - /// - /// Key-value pair to deconstruct. - /// The deconstructed key. - /// The deconstructed value. - /// Type of the key. - /// Type of the value. - public static void Deconstruct( - this KeyValuePair keyValuePair, - out TKey key, - out TValue value - ) - { - key = keyValuePair.Key; - value = keyValuePair.Value; - } - - /// - /// Adds the contents of an of type - /// to a . - /// - /// Target dictionary to add to. - /// Source enumerable to add from. - /// Type of the key. - /// Type of the value. - public static void AddRangeUnique( - this Dictionary target, - IEnumerable> source - ) - { - foreach (var kvp in source) - { - if (target.ContainsKey(kvp.Key)) - { - continue; - } - - target.Add(kvp.Key, kvp.Value); - } - } - - /// - /// Adds the contents of an of type - /// to a . If the key already exists, the contents of the value - /// enumerable will be added to the existing value enumerable. - /// - /// Target dictionary to add to. - /// Source enumerable to add from. - /// Type of the key. - /// Type of the value . - public static void AddRangeMerge( - this Dictionary> target, - IEnumerable>> source - ) - { - foreach (var kvp in source) - { - if (target.ContainsKey(kvp.Key)) - { - target[kvp.Key] = target[kvp.Key].Concat(kvp.Value); - continue; - } - - target.Add(kvp.Key, kvp.Value); - } - } - - /// - /// Gets the relative path to a working directory with both paths expressed as strings - /// - /// - /// - /// - public static string MakeRelativePathTo(this string fullPath, string workingDirectory) - { - string result = string.Empty; - int offset; - - // this is the easy case. The file is inside of the working directory. - if( fullPath.StartsWith(workingDirectory) ) - { - return fullPath.Substring(workingDirectory.Length + 1); - } - - // the hard case has to back out of the working directory - string[] baseDirs = workingDirectory.Split(':', '\\', '/'); - string[] fileDirs = fullPath.Split(':', '\\', '/'); - - // if we failed to split (empty strings?) or the drive letter does not match - if( baseDirs.Length <= 0 || fileDirs.Length <= 0 || baseDirs[0] != fileDirs[0] ) - { - // can't create a relative path between separate harddrives/partitions. - return fullPath; - } - - // skip all leading directories that match - for (offset = 1; offset < baseDirs.Length; offset++) - { - if (baseDirs[offset] != fileDirs[offset]) - break; - } - - // back out of the working directory - for (int i = 0; i < (baseDirs.Length - offset); i++) - { - result += "..\\"; - } - - // step into the file path - for (int i = offset; i < fileDirs.Length-1; i++) - { - result += fileDirs[i] + "\\"; - } - - // append the file - result += fileDirs[fileDirs.Length - 1]; - - return result; - } -} \ No newline at end of file diff --git a/src/PatchManager.Shared/Interfaces/ITextAssetGenerator.cs b/src/PatchManager.Shared/Interfaces/ITextAssetGenerator.cs deleted file mode 100644 index 28edccd..0000000 --- a/src/PatchManager.Shared/Interfaces/ITextAssetGenerator.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace PatchManager.Shared.Interfaces; - -/// -/// Describes a patcher that can generate text assets -/// -public interface ITextAssetGenerator -{ - /// - /// The priority of this patcher compared to other patchers, so it can order the way they get executed - /// - public ulong Priority { get; } - - /// - /// Creates a new text asset - /// - /// The label of the created asset - /// The name of the created asset - /// The contents of the created asset - public string Create(out string label, out string name); -} \ No newline at end of file diff --git a/src/PatchManager.Shared/Interfaces/ITextPatcher.cs b/src/PatchManager.Shared/Interfaces/ITextPatcher.cs deleted file mode 100644 index 0f0809c..0000000 --- a/src/PatchManager.Shared/Interfaces/ITextPatcher.cs +++ /dev/null @@ -1,21 +0,0 @@ -namespace PatchManager.Shared.Interfaces; - -/// -/// This interfaces describes a patcher that can patch a simple text asset -/// -public interface ITextPatcher -{ - /// - /// The priority of this patcher compared to other patchers, so it can order the way they get executed - /// - public ulong Priority { get; } - - /// - /// Execute this patcher on a blob of text - /// - /// The type of patch, "part" for parts patches, etc... - /// The name of the blob of text being patched - /// The string representation of the file being patched, if it gets set to an empty string, then we should just delete whatever is being patched - /// True if the patchData was modified - public bool TryPatch(string patchType, string name, ref string patchData); -} \ No newline at end of file diff --git a/src/PatchManager.Shared/Logging.cs b/src/PatchManager.Shared/Logging.cs deleted file mode 100644 index 33279f0..0000000 --- a/src/PatchManager.Shared/Logging.cs +++ /dev/null @@ -1,86 +0,0 @@ -using BepInEx.Logging; -using JetBrains.Annotations; - -namespace PatchManager.Shared; - -/// -/// Logging helper class for use in the PatchManager modules. -/// -[PublicAPI] -public static class Logging -{ - private static ManualLogSource _logger; - - /// - /// Initializes the logging helper class with a BepInEx log source. - /// - /// Log source to use for logging. - public static void Initialize(ManualLogSource logger) - { - _logger = logger; - } - - /// - /// Logs a message with the specified log level. - /// - /// Log level of the message. - /// Message to be logged. - public static void Log(LogLevel level, object message) - { - _logger.Log(level, message); - } - - /// - /// Logs a debug message. - /// - /// Message to be logged. - public static void LogDebug(object message) - { - Log(LogLevel.Debug, message); - } - - /// - /// Logs a message-level message. - /// - /// Message to be logged. - public static void LogMessage(object message) - { - Log(LogLevel.Message, message); - } - - /// - /// Logs an info message. - /// - /// Message to be logged. - public static void LogInfo(object message) - { - Log(LogLevel.Info, message); - } - - /// - /// Logs a warning message. - /// - /// Message to be logged. - public static void LogWarning(object message) - { - Log(LogLevel.Warning, message); - } - - /// - /// Logs an error message. - /// - /// Message to be logged. - public static void LogError(object message) - { - Log(LogLevel.Error, message); - } - - /// - /// Logs a fatal message. Only used in the case of fatal errors that will force the game to crash. - /// - /// Message to be logged. - public static void LogFatal(object message) - { - Log(LogLevel.Fatal, message); - } -} \ No newline at end of file diff --git a/src/PatchManager.Shared/Modules/BaseModule.cs b/src/PatchManager.Shared/Modules/BaseModule.cs deleted file mode 100644 index 707fa91..0000000 --- a/src/PatchManager.Shared/Modules/BaseModule.cs +++ /dev/null @@ -1,35 +0,0 @@ -using SpaceWarp.API.Configuration; -using UnityEngine.UIElements; - -namespace PatchManager.Shared.Modules; - -/// -/// Base class for PatchManager modules. -/// -public class BaseModule : IModule -{ - /// - public virtual void Init() - { - } - - /// - public virtual void Load() - { - } - - /// - public virtual void PreLoad() - { - - } - - /// - public virtual VisualElement GetDetails() => null; - - - /// - public virtual void BindConfiguration(IConfigFile modConfiguration) - { - } -} \ No newline at end of file diff --git a/src/PatchManager.Shared/Modules/IModule.cs b/src/PatchManager.Shared/Modules/IModule.cs deleted file mode 100644 index 9d23c60..0000000 --- a/src/PatchManager.Shared/Modules/IModule.cs +++ /dev/null @@ -1,42 +0,0 @@ -using JetBrains.Annotations; -using SpaceWarp.API.Configuration; -using UnityEngine.UIElements; - -namespace PatchManager.Shared.Modules; - -/// -/// Base interface for PatchManager DLL modules. -/// -public interface IModule -{ - /// - /// Called in the mod's Start method before the game is loaded. - /// Use this method to register actions with the FlowManager. - /// - public void Init(); - - /// - /// Called in mod's OnPreInitialized method after the game is loaded. - /// Use this to register resource locators and do things that require the GameInstance. - /// - public void PreLoad(); - - /// - /// Called in mod's OnInitialized method after the game is loaded. - /// Use this to register resource locators and do things that require the GameInstance. - /// - public void Load(); - - /// - /// Called when getting the details information for patch manager after game load. - /// - /// A visual element describing information about the module or null for no information - [CanBeNull] - public VisualElement GetDetails(); - - /// - /// Called to bind configuration to this module specifically. - /// - /// The configuration of the base Patch Manager mod to bind to - public void BindConfiguration(IConfigFile modConfiguration); -} \ No newline at end of file diff --git a/src/PatchManager.Shared/Modules/ModuleManager.cs b/src/PatchManager.Shared/Modules/ModuleManager.cs deleted file mode 100644 index db30d8d..0000000 --- a/src/PatchManager.Shared/Modules/ModuleManager.cs +++ /dev/null @@ -1,70 +0,0 @@ -using System.Reflection; -using JetBrains.Annotations; - -namespace PatchManager.Shared.Modules; - -/// -/// Manages the loading of PatchManager DLL modules. -/// -internal static class ModuleManager -{ - private static readonly HashSet ModulePaths = new(); - internal static readonly List Modules = new(); - - /// - /// Registers a PatchManager module DLL to be loaded. The module must contain a single class that inherits - /// from . - /// - /// Path to the module DLL file - [PublicAPI] - public static void Register(string path) - { - if (ModulePaths.Contains(path)) - { - Logging.LogError($"Module {path} is already registered."); - return; - } - - var assembly = Assembly.LoadFile(path); - var modules = assembly.ExportedTypes - .Where(type => typeof(IModule).IsAssignableFrom(type)) - .ToList(); - - if (modules.Count != 1) - { - Logging.LogError( - $"Assembly {assembly.FullName} should contain a single class implementing {typeof(IModule).FullName}" - ); - return; - } - - var instance = (IModule)Activator.CreateInstance(modules[0]); - Modules.Add(instance); - ModulePaths.Add(path); - } - - internal static void InitAll() - { - foreach (var module in Modules) - { - module.Init(); - } - } - - internal static void LoadAll() - { - foreach (var module in Modules) - { - module.Load(); - } - } - - internal static void PreLoadAll() - { - - foreach (var module in Modules) - { - module.PreLoad(); - } - } -} \ No newline at end of file diff --git a/src/PatchManager.Shared/PatchManager.Shared.csproj b/src/PatchManager.Shared/PatchManager.Shared.csproj deleted file mode 100644 index 849740f..0000000 --- a/src/PatchManager.Shared/PatchManager.Shared.csproj +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/src/PatchManager.Shared/Properties/AssemblyInfo.cs b/src/PatchManager.Shared/Properties/AssemblyInfo.cs deleted file mode 100644 index 67741a3..0000000 --- a/src/PatchManager.Shared/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,3 +0,0 @@ -using System.Runtime.CompilerServices; - -[assembly: InternalsVisibleTo("PatchManager")] \ No newline at end of file diff --git a/src/PatchManager/PatchManager.csproj b/src/PatchManager/PatchManager.csproj deleted file mode 100644 index ef5a502..0000000 --- a/src/PatchManager/PatchManager.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/PatchManager/PatchManagerPlugin.cs b/src/PatchManager/PatchManagerPlugin.cs deleted file mode 100644 index 81fdcd0..0000000 --- a/src/PatchManager/PatchManagerPlugin.cs +++ /dev/null @@ -1,131 +0,0 @@ -using System.Reflection; -using BepInEx; -using HarmonyLib; -using JetBrains.Annotations; -using PatchManager.Shared; -using PatchManager.Shared.Modules; -using SpaceWarp; -using SpaceWarp.API.Mods; -using UnityEngine.UIElements; - -namespace PatchManager; - -/// -/// Main plugin class -/// -[BepInPlugin(MyPluginInfo.PLUGIN_GUID, MyPluginInfo.PLUGIN_NAME, MyPluginInfo.PLUGIN_VERSION)] -[BepInDependency(SpaceWarpPlugin.ModGuid, SpaceWarpPlugin.ModVer)] -public class PatchManagerPlugin : BaseSpaceWarpPlugin -{ - /// - /// BepInEx GUID of the mod - /// - [PublicAPI] public const string ModGuid = MyPluginInfo.PLUGIN_GUID; - /// - /// Name of the mod - /// - [PublicAPI] public const string ModName = MyPluginInfo.PLUGIN_NAME; - /// - /// Version of the mod - /// - [PublicAPI] public const string ModVer = MyPluginInfo.PLUGIN_VERSION; - - private void Awake() - { - // Initialize logging - Logging.Initialize(Logger); - - // Load library DLLs - var path = new FileInfo(Assembly.GetExecutingAssembly().Location); - var dir = path.Directory!; - Assembly.LoadFile(Path.Combine(dir.FullName, "lib", "Antlr4.Runtime.Standard.dll")); - Assembly.LoadFile(Path.Combine(dir.FullName, "PatchManager.SassyPatching.dll")); - - // Load module DLLs - ModuleManager.Register(Path.Combine(dir.FullName, "PatchManager.Core.dll")); - ModuleManager.Register(Path.Combine(dir.FullName, "PatchManager.Parts.dll")); - ModuleManager.Register(Path.Combine(dir.FullName, "PatchManager.Generic.dll")); - ModuleManager.Register(Path.Combine(dir.FullName, "PatchManager.Resources.dll")); - ModuleManager.Register(Path.Combine(dir.FullName, "PatchManager.Science.dll")); - ModuleManager.Register(Path.Combine(dir.FullName, "PatchManager.Missions.dll")); - foreach (var module in ModuleManager.Modules) - { - module.BindConfiguration(SWConfiguration); - } - } - - private void Start() - { - // Register Harmony patches - var harmony = Harmony.CreateAndPatchAll(typeof(PatchManagerPlugin).Assembly); - foreach (var module in ModuleManager.Modules) - { - harmony.PatchAll(module.GetType().Assembly); - } - - // Init modules - ModuleManager.InitAll(); - } - - /// - /// Called before the game is initialized - /// - public override void OnPreInitialized() - { - ModuleManager.PreLoadAll(); - } - - /// - /// Called after the game is initialized - /// - public override void OnInitialized() - { - ModuleManager.LoadAll(); - } - - /// - /// Called after all mods are initialized - /// - public override void OnPostInitialized() - { - InitializePatchManagerDetailsFoldout(); - } - - private static void InitializePatchManagerDetailsFoldout() - { - VisualElement GeneratePatchManagerText() - { - var detailsContainer = new ScrollView(); - var str = "Loaded modules: "; - var toAdd = new List(); - foreach (var module in ModuleManager.Modules) - { - str += $"\n- {module.GetType().Assembly.GetName().Name}"; - var details = module.GetDetails(); - if (details != null) - { - toAdd.Add(details); - } - } - str += "\n"; - var loadedModules = new TextElement - { - text = str, - visible = true, - style = - { - display = DisplayStyle.Flex - } - }; - detailsContainer.Add(loadedModules); - foreach (var element in toAdd) - { - detailsContainer.Add(element); - } - detailsContainer.visible = true; - detailsContainer.style.display = DisplayStyle.Flex; - return detailsContainer; - } - SpaceWarp.API.UI.ModList.RegisterDetailsFoldoutGenerator(ModGuid, GeneratePatchManagerText); - } -} \ No newline at end of file From 58f52339ebcff138365770ba6e31790c771da1c8 Mon Sep 17 00:00:00 2001 From: "DANSPC\\Dan" Date: Sun, 1 Jun 2025 14:50:47 +0200 Subject: [PATCH 2/6] register Planetsmodule because for some reason it wasn't before --- Runtime/PatchManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Runtime/PatchManager.cs b/Runtime/PatchManager.cs index 4561000..c0855bd 100644 --- a/Runtime/PatchManager.cs +++ b/Runtime/PatchManager.cs @@ -30,6 +30,7 @@ public void Awake() ModuleManager.Register(typeof(PartsModule)); ModuleManager.Register(typeof(ResourcesModule)); ModuleManager.Register(typeof(ScienceModule)); + ModuleManager.Register(typeof(PlanetsModule)); Logging.Initialize(SWLogger); foreach (var module in ModuleManager.Modules) { From fa6dfba894e3c076e3b8ef3afb4b0dd12ea83879 Mon Sep 17 00:00:00 2001 From: "DANSPC\\Dan" Date: Sun, 1 Jun 2025 21:17:09 +0200 Subject: [PATCH 3/6] remove patches --- .../AtmosphereScatterManagerPatches.cs | 35 ----------- .../AtmosphereScatterManagerPatches.cs.meta | 11 ---- .../Patches/CelestialBodyBehaviorPatches.cs | 61 ------------------- .../CelestialBodyBehaviorPatches.cs.meta | 11 ---- .../Patches/CloudRenderHelperPatches.cs | 35 ----------- .../Patches/CloudRenderHelperPatches.cs.meta | 11 ---- .../ScaledCloudDataModelComponentPatches.cs | 20 ------ ...aledCloudDataModelComponentPatches.cs.meta | 11 ---- .../Planets/Shoemaker/Utility/GlobalUsings.cs | 3 - .../Shoemaker/Utility/GlobalUsings.cs.meta | 11 ---- 10 files changed, 209 deletions(-) delete mode 100644 Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs delete mode 100644 Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs.meta delete mode 100644 Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs delete mode 100644 Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs.meta delete mode 100644 Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs delete mode 100644 Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs.meta delete mode 100644 Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs delete mode 100644 Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs.meta delete mode 100644 Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs delete mode 100644 Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs.meta diff --git a/Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs b/Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs deleted file mode 100644 index bc64f61..0000000 --- a/Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs +++ /dev/null @@ -1,35 +0,0 @@ -/*using HarmonyLib; -using KSP.Game; -using KSP.Rendering; -using KSP.Rendering.Planets; -using Shoemaker; - -namespace Shoemaker.Patches -{ - //[HarmonyPatch(typeof(AtmosphereScatterManager))] - internal static class AtmosphereScatterManagerPatches - { - // [HarmonyPatch(nameof(AtmosphereScatterManager.OnAtmosphereModelLoaded))] - // [HarmonyPrefix] - internal static void OnAtmosphereModelLoaded(AtmosphereScatterManager __instance, AtmosphereModel model) - { - if (model == null) - return; - // LogInfo($"The atmosphere model for {model.PlanetName} has been loaded"); - // LogInfo($"Bottom radius: {model.BottomRadius} km"); - // LogInfo($"Height: {model.AtmosphereHeight} km"); - // LogInfo($"Absorption Height min-max: {model.AbsorptionHeightMinMax.x} - {model.AbsorptionHeightMinMax.y}"); - if (OverrideManager.AtmosphereOverrides.TryGetValue(model.PlanetName, out var @override)) - { - @override.ApplyTo(model); - // LogInfo($"Applied override to atmosphere for {model.PlanetName}: "); - // LogInfo($"Bottom radius: {model.BottomRadius} km"); - // LogInfo($"Height: {model.AtmosphereHeight} km"); - // LogInfo($"Absorption Height Min max: {model.AbsorptionHeightMinMax.x} - {model.AbsorptionHeightMinMax.y}"); - } - } - } -} - -*/ -// since we aren't locked to the confines of Harmony Patching we can just add these changes already \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs.meta b/Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs.meta deleted file mode 100644 index 099c171..0000000 --- a/Runtime/Planets/Shoemaker/Patches/AtmosphereScatterManagerPatches.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ec9e8c3237ae58a4bab84e398a6cc540 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs b/Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs deleted file mode 100644 index 732d7d7..0000000 --- a/Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs +++ /dev/null @@ -1,61 +0,0 @@ -/*//using HarmonyLib; -using KSP; -using KSP.Game; -using KSP.Sim.impl; -using UnityEngine; - -namespace Shoemaker.Patches -{ - [HarmonyPatch(typeof(CelestialBodyBehavior))] - internal static class CelestialBodyBehaviourPatches - { - [HarmonyPatch(nameof(CelestialBodyBehavior.OnScaledSpaceViewInstantiated))] - [HarmonyPrefix] - internal static void MergeData(CelestialBodyBehavior __instance, GameObject instance) - { - - } - - [HarmonyPatch(nameof(CelestialBodyBehavior.OnLocalSpaceViewInstantiated))] - [HarmonyPrefix] - internal static void LogStuff(CelestialBodyBehavior __instance, GameObject obj) - { - LogInfo( - $"Following info is from the local space load of {__instance.CelestialBodyData.Data.bodyName}"); - LogInfo($"The celestial body has a radius of {__instance.CelestialBodyData.Data.radius}"); - LogInfo("The local space object has the following components:\n"); - foreach (var component in obj.GetComponents(typeof(UnityObject))) - { - LogInfo($"- {component.GetType()}"); - } - - // LogInfo($"The local space has the following prefabs\n"); - // if (obj.TryGetComponent(out NestedPrefabSpawner nestedPrefabSpawner)) - // { - // foreach (var prefab in nestedPrefabSpawner.Prefabs) - // { - // LogInfo($"- {prefab.PrefabAssetReference.AssetGUID}"); - // if (prefab.tgtTransform != null) - // { - // LogInfo($"\t- {prefab.tgtTransform.name}"); - // var operation = prefab.PrefabAssetReference.InstantiateAsync(); - // operation.Completed += x => - // { - // LogInfo($"From previous async handle for {prefab.PrefabAssetReference.AssetGUID}"); - // var surfaceObject = x.Result.GetComponent(); - // LogInfo($"Latitude - {surfaceObject.Latitude}"); - // LogInfo($"Longitude - {surfaceObject.Longitude}"); - // LogInfo($"Radial Offset - {surfaceObject.RadialOffset}"); - // LogInfo($"Degrees around radial normal - {surfaceObject.DegreesAroundRadialNormal}"); - // x.Result.DestroyGameObject(); - // }; - // } - // } - // } - // var scale = OverrideManager.Scales[__instance.CelestialBodyData.Data.bodyName]; - - // obj.transform.localScale *= (float)scale; - } - - } -}*/ \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs.meta b/Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs.meta deleted file mode 100644 index 05f9100..0000000 --- a/Runtime/Planets/Shoemaker/Patches/CelestialBodyBehaviorPatches.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 9457beb8a75ad4e41b5f61d51ee72ec3 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs b/Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs deleted file mode 100644 index d7ad8d7..0000000 --- a/Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System.Reflection; -using System.Reflection.Emit; -/*using HarmonyLib; -using KSP.VolumeCloud; -using UnityEngine.ResourceManagement.AsyncOperations; - -namespace Shoemaker.Patches -{ - public static class CloudRenderHelperPatches - { - // [HarmonyPatch(typeof(CloudRenderHelper))] - // [HarmonyPatch(nameof(CloudRenderHelper.LoadingConfigCompleted))] - // [HarmonyTranspiler] - // public static IEnumerable ModifyFunction(IEnumerable instructions) - // { - // yield return new CodeInstruction(OpCodes.Ldarg_1); - // yield return new CodeInstruction(OpCodes.Call,typeof(CloudRenderHelper).GetMethod(nameof(UpdateConfiguration),BindingFlags.Public | BindingFlags.Static)); - // foreach (var instruction in instructions) - // { - // yield return instruction; - // } - // } - - public static void UpdateConfiguration(AsyncOperationHandle configurationHandle) - { - if (configurationHandle.Status != AsyncOperationStatus.Succeeded) return; - var bodyName = configurationHandle.Result.bodyName; - if (!OverrideManager.VolumeCloudOverrides.TryGetValue(bodyName.ToLowerInvariant(), - out var volumeCloudConfigurationOverride)) return; - // LogInfo($"Found a configuration override for {bodyName}"); - volumeCloudConfigurationOverride.ApplyTo(configurationHandle.Result); - } - } -}*/ - diff --git a/Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs.meta b/Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs.meta deleted file mode 100644 index 1df8b04..0000000 --- a/Runtime/Planets/Shoemaker/Patches/CloudRenderHelperPatches.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: c857f7336fe9b9644a8bb0260e782a82 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs b/Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs deleted file mode 100644 index 0f8ba09..0000000 --- a/Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs +++ /dev/null @@ -1,20 +0,0 @@ -// HarmonyLib; -//using KSP; -//using KSP.Game; -//using KSP.Rendering; -//using UnityEngine; - -//namespace Shoemaker.Patches -//{ - //[HarmonyPatch(typeof(ScaledCloudDataModelComponent))] -// internal static class ScaledCloudDataModelComponentPatches -/// { - // [HarmonyPatch(nameof(ScaledCloudDataModelComponent.Initialize))] - // [HarmonyPrefix] - // public static void UpdateCoreCelestialBodyData(ScaledCloudDataModelComponent __instance) - // { - - // } -// } -//} - diff --git a/Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs.meta b/Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs.meta deleted file mode 100644 index 0c5d4e6..0000000 --- a/Runtime/Planets/Shoemaker/Patches/ScaledCloudDataModelComponentPatches.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: e3c14f71403e67d468003ed02fd6f998 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs b/Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs deleted file mode 100644 index 9f4ca3c..0000000 --- a/Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs +++ /dev/null @@ -1,3 +0,0 @@ -//global using static Shoemaker.Utility.Logging; -//global using UnityObject = UnityEngine.Object; -//global using static Shoemaker.Utility.Extensions; \ No newline at end of file diff --git a/Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs.meta b/Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs.meta deleted file mode 100644 index 1e36a79..0000000 --- a/Runtime/Planets/Shoemaker/Utility/GlobalUsings.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: ace6a495938122248a1f925693787d2f -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: From 72d97e85b55207713dfe7e2e3db4ab87a354ff5d Mon Sep 17 00:00:00 2001 From: "DANSPC\\Dan" Date: Tue, 3 Jun 2025 16:41:07 +0200 Subject: [PATCH 4/6] CumulusData editing --- .../Shoemaker/Overrides/CloudsDataOverride.cs | 62 ++++++++++++++----- .../VolumeCloudConfigurationOverride.cs | 1 - 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs b/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs index 3a4253f..df3dd04 100644 --- a/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs +++ b/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs @@ -4,6 +4,7 @@ using JetBrains.Annotations; using KSP.VolumeCloud; using UnityEngine; +using static Shoemaker.Utility.Extensions; namespace Shoemaker.Overrides { @@ -25,23 +26,54 @@ public class CloudsDataOverride : IOverride public float? evolveSpeed; public float? topOffset; public bool? isFold; - + public float? baseTexureTile; + public float? coverageScale; + public float? evanish; + public float? detailAmount; + public float? cloudsMaskBias; + public float? upperFalloff; + public float? lowerFalloff; + public float? detailAltitudeShift; + public bool? enableDetailTexture; + public float? detailTextureTile; + public float? detailStrength; + public float? cloudsDensity; + public float? normalScale; + public Color? scaleCloudColor = Color.white; + public void ApplyTo(VolumeCloudConfiguration.CloudsData obj) { - isEnable.Apply(value => obj.isEnable = value ?? false); - castShadow.Apply(value => obj.castShadow = value ?? false); - bakeCloudMipmap.Apply(value => obj.bakeCloudMipmap = value ?? 0); - currentBakedCloudMipMap.Apply(value => obj.currentBakedCloudMipmap = value ?? 0); - cloudsType.Apply(value => obj.cloudsType = value ?? VolumeCloudConfiguration.CloudsLayerType.Cumulus); - cloudHeightRange.Apply(value => obj.cloudHeightRange = value ?? Vector2.zero); - bakedCloudHeight.Apply(value => obj.bakedCloudHeight = value ?? 0); - cloudsLayerRotate.Apply(value => obj.cloudsLayerRotate = value ?? Vector3.zero); - enableWind.Apply(value => obj.enableWind = value ?? false); - windDirection.Apply(value => obj.windDirection = value ?? Vector2.zero); - movementSpeed.Apply(value => obj.movementSpeed = value ?? 0f); - evolveSpeed.Apply(value => obj.evolveSpeed = value ?? 0f); - topOffset.Apply(value => obj.topOffset = value ?? 0f); - isFold.Apply(value => obj.isFold = value ?? false); + isEnable.Apply(ref obj.isEnable); + castShadow.Apply(ref obj.castShadow); + bakeCloudMipmap.Apply(ref obj.bakeCloudMipmap); + currentBakedCloudMipMap.Apply(ref obj.currentBakedCloudMipmap); + cloudsType.Apply(ref obj.cloudsType); + cloudHeightRange.Apply(ref obj.cloudHeightRange); + bakedCloudHeight.Apply(ref obj.bakedCloudHeight); + cloudsLayerRotate.Apply(ref obj.cloudsLayerRotate); + enableWind.Apply(ref obj.enableWind); + windDirection.Apply(ref obj.windDirection); + movementSpeed.Apply(ref obj.movementSpeed); + evolveSpeed.Apply(ref obj.evolveSpeed); + topOffset.Apply(ref obj.topOffset); + isFold.Apply(ref obj.isFold); + if (obj is VolumeCloudConfiguration.CumulusData cumulus) + { + baseTexureTile.Apply(ref cumulus.baseTexureTile); + coverageScale.Apply(ref cumulus.coverageScale); + evanish.Apply(ref cumulus.evanish); + detailAmount.Apply(ref cumulus.detailAmount); + cloudsMaskBias.Apply(ref cumulus.cloudsMaskBias); + upperFalloff.Apply(ref cumulus.upperFalloff); + lowerFalloff.Apply(ref cumulus.lowerFalloff); + detailAltitudeShift.Apply(ref cumulus.detailAltitudeShift); + enableDetailTexture.Apply(ref cumulus.enableDetailTexture); + detailTextureTile.Apply(ref cumulus.detailTextureTile); + detailStrength.Apply(ref cumulus.detailStrength); + cloudsDensity.Apply(ref cumulus.cloudsDensity); + normalScale.Apply(ref cumulus.normalScale); + scaleCloudColor.Apply(ref cumulus.scaleCloudColor); + } } } } diff --git a/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs b/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs index 3646ea8..6f81771 100644 --- a/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs +++ b/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs @@ -26,7 +26,6 @@ public class VolumeCloudConfigurationOverride : IOverride cumulusList = new List(); - // todo: cumulus list // todo: cumulus index public float? cloudCoverageModifier; public float? detailVariationRange; From 79aef7f67f2f9e217363d215c289511e13beae9a Mon Sep 17 00:00:00 2001 From: "DANSPC\\Dan" Date: Tue, 3 Jun 2025 20:45:29 +0200 Subject: [PATCH 5/6] re-order stuff and fix namespaces --- .../Planets/{Shoemaker => }/Directory.Build.targets.meta | 0 Runtime/Planets/{Shoemaker => }/Modifiables.meta | 0 .../Modifiables/AtmosphereOverrideModifiable.cs | 4 ++-- .../Modifiables/AtmosphereOverrideModifiable.cs.meta | 0 .../{Shoemaker => }/Modifiables/CelestialBodyModifiable.cs | 4 ++-- .../Modifiables/CelestialBodyModifiable.cs.meta | 0 .../{Shoemaker => }/Modifiables/GalaxyModifiable.cs | 4 ++-- .../{Shoemaker => }/Modifiables/GalaxyModifiable.cs.meta | 0 .../Modifiables/VolumeCloudOverrideModifiable.cs | 4 ++-- .../Modifiables/VolumeCloudOverrideModifiable.cs.meta | 0 Runtime/Planets/{Shoemaker => }/OverrideManager.cs | 6 ++---- Runtime/Planets/{Shoemaker => }/OverrideManager.cs.meta | 0 Runtime/Planets/{Shoemaker => }/Overrides.meta | 0 .../{Shoemaker => }/Overrides/AtmosphereOverride.cs | 2 +- .../{Shoemaker => }/Overrides/AtmosphereOverride.cs.meta | 0 .../{Shoemaker => }/Overrides/CloudsDataOverride.cs | 4 ++-- .../{Shoemaker => }/Overrides/CloudsDataOverride.cs.meta | 0 Runtime/Planets/{Shoemaker => }/Overrides/IOverride.cs | 2 +- .../Planets/{Shoemaker => }/Overrides/IOverride.cs.meta | 0 .../Overrides/VolumeCloudConfigurationOverride.cs | 4 ++-- .../Overrides/VolumeCloudConfigurationOverride.cs.meta | 0 Runtime/Planets/{Shoemaker => }/Patches.meta | 0 Runtime/Planets/{Shoemaker => }/PlanetsModule.cs | 4 ++-- Runtime/Planets/{Shoemaker => }/PlanetsModule.cs.meta | 0 Runtime/Planets/{Shoemaker => }/Rulesets.meta | 0 .../{Shoemaker => }/Rulesets/AtmosphereOverrideRuleset.cs | 6 +++--- .../Rulesets/AtmosphereOverrideRuleset.cs.meta | 0 .../{Shoemaker => }/Rulesets/CelestialBodyRuleset.cs | 4 ++-- .../{Shoemaker => }/Rulesets/CelestialBodyRuleset.cs.meta | 0 Runtime/Planets/{Shoemaker => }/Rulesets/GalaxyRuleset.cs | 4 ++-- .../Planets/{Shoemaker => }/Rulesets/GalaxyRuleset.cs.meta | 0 .../{Shoemaker => }/Rulesets/VolumeCloudOverrideRuleset.cs | 6 +++--- .../Rulesets/VolumeCloudOverrideRuleset.cs.meta | 0 Runtime/Planets/{Shoemaker => }/Selectables.meta | 0 .../Selectables/AtmosphereOverrideSelectable.cs | 4 ++-- .../Selectables/AtmosphereOverrideSelectable.cs.meta | 0 .../{Shoemaker => }/Selectables/CelestialBodySelectable.cs | 4 ++-- .../Selectables/CelestialBodySelectable.cs.meta | 0 .../{Shoemaker => }/Selectables/GalaxySelectable.cs | 4 ++-- .../{Shoemaker => }/Selectables/GalaxySelectable.cs.meta | 0 .../{Shoemaker => }/Selectables/VolumeCloudSelectable.cs | 6 +++--- .../Selectables/VolumeCloudSelectable.cs.meta | 0 Runtime/Planets/{Shoemaker => }/Shoemaker.csproj | 0 Runtime/Planets/{Shoemaker => }/Shoemaker.csproj.meta | 0 Runtime/Planets/{Shoemaker => }/Utility.meta | 0 Runtime/Planets/{Shoemaker => }/Utility/Extensions.cs | 2 +- Runtime/Planets/{Shoemaker => }/Utility/Extensions.cs.meta | 0 Runtime/Planets/{Shoemaker => }/swinfo.json | 0 Runtime/Planets/{Shoemaker => }/swinfo.json.meta | 0 .../Planets/Shoemaker.meta => scripts/build-debug.bat.meta | 3 +-- scripts/build-deploy.bat.meta | 7 +++++++ scripts/build-release.bat.meta | 7 +++++++ scripts/build-run.bat.meta | 7 +++++++ 53 files changed, 60 insertions(+), 42 deletions(-) rename Runtime/Planets/{Shoemaker => }/Directory.Build.targets.meta (100%) rename Runtime/Planets/{Shoemaker => }/Modifiables.meta (100%) rename Runtime/Planets/{Shoemaker => }/Modifiables/AtmosphereOverrideModifiable.cs (91%) rename Runtime/Planets/{Shoemaker => }/Modifiables/AtmosphereOverrideModifiable.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Modifiables/CelestialBodyModifiable.cs (91%) rename Runtime/Planets/{Shoemaker => }/Modifiables/CelestialBodyModifiable.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Modifiables/GalaxyModifiable.cs (91%) rename Runtime/Planets/{Shoemaker => }/Modifiables/GalaxyModifiable.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Modifiables/VolumeCloudOverrideModifiable.cs (91%) rename Runtime/Planets/{Shoemaker => }/Modifiables/VolumeCloudOverrideModifiable.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/OverrideManager.cs (84%) rename Runtime/Planets/{Shoemaker => }/OverrideManager.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Overrides.meta (100%) rename Runtime/Planets/{Shoemaker => }/Overrides/AtmosphereOverride.cs (99%) rename Runtime/Planets/{Shoemaker => }/Overrides/AtmosphereOverride.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Overrides/CloudsDataOverride.cs (97%) rename Runtime/Planets/{Shoemaker => }/Overrides/CloudsDataOverride.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Overrides/IOverride.cs (71%) rename Runtime/Planets/{Shoemaker => }/Overrides/IOverride.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Overrides/VolumeCloudConfigurationOverride.cs (98%) rename Runtime/Planets/{Shoemaker => }/Overrides/VolumeCloudConfigurationOverride.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Patches.meta (100%) rename Runtime/Planets/{Shoemaker => }/PlanetsModule.cs (95%) rename Runtime/Planets/{Shoemaker => }/PlanetsModule.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Rulesets.meta (100%) rename Runtime/Planets/{Shoemaker => }/Rulesets/AtmosphereOverrideRuleset.cs (90%) rename Runtime/Planets/{Shoemaker => }/Rulesets/AtmosphereOverrideRuleset.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Rulesets/CelestialBodyRuleset.cs (93%) rename Runtime/Planets/{Shoemaker => }/Rulesets/CelestialBodyRuleset.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Rulesets/GalaxyRuleset.cs (94%) rename Runtime/Planets/{Shoemaker => }/Rulesets/GalaxyRuleset.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Rulesets/VolumeCloudOverrideRuleset.cs (89%) rename Runtime/Planets/{Shoemaker => }/Rulesets/VolumeCloudOverrideRuleset.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Selectables.meta (100%) rename Runtime/Planets/{Shoemaker => }/Selectables/AtmosphereOverrideSelectable.cs (97%) rename Runtime/Planets/{Shoemaker => }/Selectables/AtmosphereOverrideSelectable.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Selectables/CelestialBodySelectable.cs (97%) rename Runtime/Planets/{Shoemaker => }/Selectables/CelestialBodySelectable.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Selectables/GalaxySelectable.cs (98%) rename Runtime/Planets/{Shoemaker => }/Selectables/GalaxySelectable.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Selectables/VolumeCloudSelectable.cs (96%) rename Runtime/Planets/{Shoemaker => }/Selectables/VolumeCloudSelectable.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/Shoemaker.csproj (100%) rename Runtime/Planets/{Shoemaker => }/Shoemaker.csproj.meta (100%) rename Runtime/Planets/{Shoemaker => }/Utility.meta (100%) rename Runtime/Planets/{Shoemaker => }/Utility/Extensions.cs (84%) rename Runtime/Planets/{Shoemaker => }/Utility/Extensions.cs.meta (100%) rename Runtime/Planets/{Shoemaker => }/swinfo.json (100%) rename Runtime/Planets/{Shoemaker => }/swinfo.json.meta (100%) rename Runtime/Planets/Shoemaker.meta => scripts/build-debug.bat.meta (67%) create mode 100644 scripts/build-deploy.bat.meta create mode 100644 scripts/build-release.bat.meta create mode 100644 scripts/build-run.bat.meta diff --git a/Runtime/Planets/Shoemaker/Directory.Build.targets.meta b/Runtime/Planets/Directory.Build.targets.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Directory.Build.targets.meta rename to Runtime/Planets/Directory.Build.targets.meta diff --git a/Runtime/Planets/Shoemaker/Modifiables.meta b/Runtime/Planets/Modifiables.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Modifiables.meta rename to Runtime/Planets/Modifiables.meta diff --git a/Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs b/Runtime/Planets/Modifiables/AtmosphereOverrideModifiable.cs similarity index 91% rename from Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs rename to Runtime/Planets/Modifiables/AtmosphereOverrideModifiable.cs index 06964e4..ded738e 100644 --- a/Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs +++ b/Runtime/Planets/Modifiables/AtmosphereOverrideModifiable.cs @@ -1,8 +1,8 @@ using PatchManager.SassyPatching; using PatchManager.SassyPatching.Modifiables; -using Shoemaker.Selectables; +using PatchManager.Planets.Selectables; -namespace Shoemaker.Modifiables +namespace PatchManager.Planets.Modifiables { public class AtmosphereOverrideModifiable : JTokenModifiable { diff --git a/Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs.meta b/Runtime/Planets/Modifiables/AtmosphereOverrideModifiable.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Modifiables/AtmosphereOverrideModifiable.cs.meta rename to Runtime/Planets/Modifiables/AtmosphereOverrideModifiable.cs.meta diff --git a/Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs b/Runtime/Planets/Modifiables/CelestialBodyModifiable.cs similarity index 91% rename from Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs rename to Runtime/Planets/Modifiables/CelestialBodyModifiable.cs index 37d3ed5..3a03f47 100644 --- a/Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs +++ b/Runtime/Planets/Modifiables/CelestialBodyModifiable.cs @@ -1,8 +1,8 @@ using PatchManager.SassyPatching; using PatchManager.SassyPatching.Modifiables; -using Shoemaker.Selectables; +using PatchManager.Planets.Selectables; -namespace Shoemaker.Modifiables +namespace PatchManager.Planets.Modifiables { public class CelestialBodyModifiable : JTokenModifiable { diff --git a/Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs.meta b/Runtime/Planets/Modifiables/CelestialBodyModifiable.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Modifiables/CelestialBodyModifiable.cs.meta rename to Runtime/Planets/Modifiables/CelestialBodyModifiable.cs.meta diff --git a/Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs b/Runtime/Planets/Modifiables/GalaxyModifiable.cs similarity index 91% rename from Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs rename to Runtime/Planets/Modifiables/GalaxyModifiable.cs index f6457e8..2e48a82 100644 --- a/Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs +++ b/Runtime/Planets/Modifiables/GalaxyModifiable.cs @@ -1,8 +1,8 @@ using PatchManager.SassyPatching; using PatchManager.SassyPatching.Modifiables; -using Shoemaker.Selectables; +using PatchManager.Planets.Selectables; -namespace Shoemaker.Modifiables +namespace PatchManager.Planets.Modifiables { public class GalaxyModifiable : JTokenModifiable { diff --git a/Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs.meta b/Runtime/Planets/Modifiables/GalaxyModifiable.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Modifiables/GalaxyModifiable.cs.meta rename to Runtime/Planets/Modifiables/GalaxyModifiable.cs.meta diff --git a/Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs b/Runtime/Planets/Modifiables/VolumeCloudOverrideModifiable.cs similarity index 91% rename from Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs rename to Runtime/Planets/Modifiables/VolumeCloudOverrideModifiable.cs index 037de0f..f7aa67a 100644 --- a/Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs +++ b/Runtime/Planets/Modifiables/VolumeCloudOverrideModifiable.cs @@ -1,8 +1,8 @@ using PatchManager.SassyPatching; using PatchManager.SassyPatching.Modifiables; -using Shoemaker.Selectables; +using PatchManager.Planets.Selectables; -namespace Shoemaker.Modifiables +namespace PatchManager.Planets.Modifiables { public class VolumeCloudOverrideModifiable : JTokenModifiable { diff --git a/Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs.meta b/Runtime/Planets/Modifiables/VolumeCloudOverrideModifiable.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Modifiables/VolumeCloudOverrideModifiable.cs.meta rename to Runtime/Planets/Modifiables/VolumeCloudOverrideModifiable.cs.meta diff --git a/Runtime/Planets/Shoemaker/OverrideManager.cs b/Runtime/Planets/OverrideManager.cs similarity index 84% rename from Runtime/Planets/Shoemaker/OverrideManager.cs rename to Runtime/Planets/OverrideManager.cs index eee8684..c74d172 100644 --- a/Runtime/Planets/Shoemaker/OverrideManager.cs +++ b/Runtime/Planets/OverrideManager.cs @@ -1,9 +1,8 @@ using System.Collections.Generic; using JetBrains.Annotations; -using KSP.VolumeCloud; -using Shoemaker.Overrides; +using PatchManager.Planets.Overrides; -namespace Shoemaker +namespace PatchManager.Planets { [PublicAPI] public static class OverrideManager @@ -11,7 +10,6 @@ public static class OverrideManager public static Dictionary AtmosphereOverrides = new(); public static Dictionary Scales = new(); public static Dictionary VolumeCloudOverrides = new(); - } } diff --git a/Runtime/Planets/Shoemaker/OverrideManager.cs.meta b/Runtime/Planets/OverrideManager.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/OverrideManager.cs.meta rename to Runtime/Planets/OverrideManager.cs.meta diff --git a/Runtime/Planets/Shoemaker/Overrides.meta b/Runtime/Planets/Overrides.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Overrides.meta rename to Runtime/Planets/Overrides.meta diff --git a/Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs b/Runtime/Planets/Overrides/AtmosphereOverride.cs similarity index 99% rename from Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs rename to Runtime/Planets/Overrides/AtmosphereOverride.cs index 05a94ca..dc86ce8 100644 --- a/Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs +++ b/Runtime/Planets/Overrides/AtmosphereOverride.cs @@ -3,7 +3,7 @@ using KSP.Rendering; using UnityEngine; -namespace Shoemaker.Overrides +namespace PatchManager.Planets.Overrides { [PublicAPI] [UsedImplicitly] diff --git a/Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs.meta b/Runtime/Planets/Overrides/AtmosphereOverride.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Overrides/AtmosphereOverride.cs.meta rename to Runtime/Planets/Overrides/AtmosphereOverride.cs.meta diff --git a/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs b/Runtime/Planets/Overrides/CloudsDataOverride.cs similarity index 97% rename from Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs rename to Runtime/Planets/Overrides/CloudsDataOverride.cs index df3dd04..65a008c 100644 --- a/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs +++ b/Runtime/Planets/Overrides/CloudsDataOverride.cs @@ -4,9 +4,9 @@ using JetBrains.Annotations; using KSP.VolumeCloud; using UnityEngine; -using static Shoemaker.Utility.Extensions; +using static PatchManager.Planets.Utility.Extensions; -namespace Shoemaker.Overrides +namespace PatchManager.Planets.Overrides { [PublicAPI] public class CloudsDataOverride : IOverride diff --git a/Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs.meta b/Runtime/Planets/Overrides/CloudsDataOverride.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Overrides/CloudsDataOverride.cs.meta rename to Runtime/Planets/Overrides/CloudsDataOverride.cs.meta diff --git a/Runtime/Planets/Shoemaker/Overrides/IOverride.cs b/Runtime/Planets/Overrides/IOverride.cs similarity index 71% rename from Runtime/Planets/Shoemaker/Overrides/IOverride.cs rename to Runtime/Planets/Overrides/IOverride.cs index 1cc10a5..9839e08 100644 --- a/Runtime/Planets/Shoemaker/Overrides/IOverride.cs +++ b/Runtime/Planets/Overrides/IOverride.cs @@ -1,4 +1,4 @@ -namespace Shoemaker.Overrides +namespace PatchManager.Planets.Overrides { public interface IOverride where T : class { diff --git a/Runtime/Planets/Shoemaker/Overrides/IOverride.cs.meta b/Runtime/Planets/Overrides/IOverride.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Overrides/IOverride.cs.meta rename to Runtime/Planets/Overrides/IOverride.cs.meta diff --git a/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs b/Runtime/Planets/Overrides/VolumeCloudConfigurationOverride.cs similarity index 98% rename from Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs rename to Runtime/Planets/Overrides/VolumeCloudConfigurationOverride.cs index 6f81771..2d93c2e 100644 --- a/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs +++ b/Runtime/Planets/Overrides/VolumeCloudConfigurationOverride.cs @@ -3,12 +3,12 @@ using JetBrains.Annotations; using KSP.VolumeCloud; using UnityEngine; -using static Shoemaker.Utility.Extensions; +using static PatchManager.Planets.Utility.Extensions; // ReSharper disable InconsistentNaming // ReSharper disable IdentifierTypo -namespace Shoemaker.Overrides +namespace PatchManager.Planets.Overrides { [PublicAPI] public class VolumeCloudConfigurationOverride : IOverride diff --git a/Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs.meta b/Runtime/Planets/Overrides/VolumeCloudConfigurationOverride.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Overrides/VolumeCloudConfigurationOverride.cs.meta rename to Runtime/Planets/Overrides/VolumeCloudConfigurationOverride.cs.meta diff --git a/Runtime/Planets/Shoemaker/Patches.meta b/Runtime/Planets/Patches.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Patches.meta rename to Runtime/Planets/Patches.meta diff --git a/Runtime/Planets/Shoemaker/PlanetsModule.cs b/Runtime/Planets/PlanetsModule.cs similarity index 95% rename from Runtime/Planets/Shoemaker/PlanetsModule.cs rename to Runtime/Planets/PlanetsModule.cs index 3f4e8ce..683061e 100644 --- a/Runtime/Planets/Shoemaker/PlanetsModule.cs +++ b/Runtime/Planets/PlanetsModule.cs @@ -4,11 +4,11 @@ using KSP.IO; using Newtonsoft.Json; using PatchManager.Shared.Modules; -using Shoemaker.Overrides; +using PatchManager.Planets.Overrides; using UnityEngine; using UnityEngine.AddressableAssets; -namespace Shoemaker +namespace PatchManager.Planets { public class PlanetsModule : BaseModule { diff --git a/Runtime/Planets/Shoemaker/PlanetsModule.cs.meta b/Runtime/Planets/PlanetsModule.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/PlanetsModule.cs.meta rename to Runtime/Planets/PlanetsModule.cs.meta diff --git a/Runtime/Planets/Shoemaker/Rulesets.meta b/Runtime/Planets/Rulesets.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Rulesets.meta rename to Runtime/Planets/Rulesets.meta diff --git a/Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs b/Runtime/Planets/Rulesets/AtmosphereOverrideRuleset.cs similarity index 90% rename from Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs rename to Runtime/Planets/Rulesets/AtmosphereOverrideRuleset.cs index 4ffd260..6de348f 100644 --- a/Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs +++ b/Runtime/Planets/Rulesets/AtmosphereOverrideRuleset.cs @@ -4,10 +4,10 @@ using PatchManager.SassyPatching.Attributes; using PatchManager.SassyPatching.Interfaces; using PatchManager.SassyPatching.NewAssets; -using Shoemaker.Overrides; -using Shoemaker.Selectables; +using PatchManager.Planets.Overrides; +using PatchManager.Planets.Selectables; -namespace Shoemaker.Rulesets +namespace PatchManager.Planets.Rulesets { [PatcherRuleset("atmosphere-override","atmosphere_overrides")] public class AtmosphereOverrideRuleset : IPatcherRuleSet diff --git a/Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs.meta b/Runtime/Planets/Rulesets/AtmosphereOverrideRuleset.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Rulesets/AtmosphereOverrideRuleset.cs.meta rename to Runtime/Planets/Rulesets/AtmosphereOverrideRuleset.cs.meta diff --git a/Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs b/Runtime/Planets/Rulesets/CelestialBodyRuleset.cs similarity index 93% rename from Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs rename to Runtime/Planets/Rulesets/CelestialBodyRuleset.cs index a23ee4b..2f92d7b 100644 --- a/Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs +++ b/Runtime/Planets/Rulesets/CelestialBodyRuleset.cs @@ -5,9 +5,9 @@ using PatchManager.SassyPatching.Attributes; using PatchManager.SassyPatching.Interfaces; using PatchManager.SassyPatching.NewAssets; -using Shoemaker.Selectables; +using PatchManager.Planets.Selectables; -namespace Shoemaker.Rulesets +namespace PatchManager.Planets.Rulesets { [PatcherRuleset("body","celestial_bodies")] public class CelestialBodyRuleset : IPatcherRuleSet diff --git a/Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs.meta b/Runtime/Planets/Rulesets/CelestialBodyRuleset.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Rulesets/CelestialBodyRuleset.cs.meta rename to Runtime/Planets/Rulesets/CelestialBodyRuleset.cs.meta diff --git a/Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs b/Runtime/Planets/Rulesets/GalaxyRuleset.cs similarity index 94% rename from Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs rename to Runtime/Planets/Rulesets/GalaxyRuleset.cs index 1a627af..b927bcb 100644 --- a/Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs +++ b/Runtime/Planets/Rulesets/GalaxyRuleset.cs @@ -5,9 +5,9 @@ using PatchManager.SassyPatching.Attributes; using PatchManager.SassyPatching.Interfaces; using PatchManager.SassyPatching.NewAssets; -using Shoemaker.Selectables; +using PatchManager.Planets.Selectables; -namespace Shoemaker.Rulesets +namespace PatchManager.Planets.Rulesets { /// [PatcherRuleset("galaxy", "GalaxyDefinition_Default")] diff --git a/Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs.meta b/Runtime/Planets/Rulesets/GalaxyRuleset.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Rulesets/GalaxyRuleset.cs.meta rename to Runtime/Planets/Rulesets/GalaxyRuleset.cs.meta diff --git a/Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs b/Runtime/Planets/Rulesets/VolumeCloudOverrideRuleset.cs similarity index 89% rename from Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs rename to Runtime/Planets/Rulesets/VolumeCloudOverrideRuleset.cs index 1edb6ca..118457f 100644 --- a/Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs +++ b/Runtime/Planets/Rulesets/VolumeCloudOverrideRuleset.cs @@ -4,10 +4,10 @@ using PatchManager.SassyPatching.Attributes; using PatchManager.SassyPatching.Interfaces; using PatchManager.SassyPatching.NewAssets; -using Shoemaker.Overrides; -using Shoemaker.Selectables; +using PatchManager.Planets.Overrides; +using PatchManager.Planets.Selectables; -namespace Shoemaker.Rulesets +namespace PatchManager.Planets.Rulesets { [PatcherRuleset("volume-cloud-override","volume_cloud_overrides")] public class VolumeCloudOverrideRuleset : IPatcherRuleSet diff --git a/Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs.meta b/Runtime/Planets/Rulesets/VolumeCloudOverrideRuleset.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Rulesets/VolumeCloudOverrideRuleset.cs.meta rename to Runtime/Planets/Rulesets/VolumeCloudOverrideRuleset.cs.meta diff --git a/Runtime/Planets/Shoemaker/Selectables.meta b/Runtime/Planets/Selectables.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Selectables.meta rename to Runtime/Planets/Selectables.meta diff --git a/Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs b/Runtime/Planets/Selectables/AtmosphereOverrideSelectable.cs similarity index 97% rename from Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs rename to Runtime/Planets/Selectables/AtmosphereOverrideSelectable.cs index dc248d0..ab1d959 100644 --- a/Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs +++ b/Runtime/Planets/Selectables/AtmosphereOverrideSelectable.cs @@ -3,9 +3,9 @@ using Newtonsoft.Json.Linq; using PatchManager.SassyPatching; using PatchManager.SassyPatching.Interfaces; -using Shoemaker.Modifiables; +using PatchManager.Planets.Modifiables; -namespace Shoemaker.Selectables +namespace PatchManager.Planets.Selectables { public sealed class AtmosphereOverrideSelectable : BaseSelectable { diff --git a/Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs.meta b/Runtime/Planets/Selectables/AtmosphereOverrideSelectable.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Selectables/AtmosphereOverrideSelectable.cs.meta rename to Runtime/Planets/Selectables/AtmosphereOverrideSelectable.cs.meta diff --git a/Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs b/Runtime/Planets/Selectables/CelestialBodySelectable.cs similarity index 97% rename from Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs rename to Runtime/Planets/Selectables/CelestialBodySelectable.cs index 06816a4..de17918 100644 --- a/Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs +++ b/Runtime/Planets/Selectables/CelestialBodySelectable.cs @@ -3,9 +3,9 @@ using PatchManager.SassyPatching; using PatchManager.SassyPatching.Interfaces; using PatchManager.SassyPatching.Selectables; -using Shoemaker.Modifiables; +using PatchManager.Planets.Modifiables; -namespace Shoemaker.Selectables +namespace PatchManager.Planets.Selectables { public sealed class CelestialBodySelectable : BaseSelectable { diff --git a/Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs.meta b/Runtime/Planets/Selectables/CelestialBodySelectable.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Selectables/CelestialBodySelectable.cs.meta rename to Runtime/Planets/Selectables/CelestialBodySelectable.cs.meta diff --git a/Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs b/Runtime/Planets/Selectables/GalaxySelectable.cs similarity index 98% rename from Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs rename to Runtime/Planets/Selectables/GalaxySelectable.cs index 6ed2813..b046f0e 100644 --- a/Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs +++ b/Runtime/Planets/Selectables/GalaxySelectable.cs @@ -4,9 +4,9 @@ using PatchManager.SassyPatching; using PatchManager.SassyPatching.Interfaces; using PatchManager.SassyPatching.Selectables; -using Shoemaker.Modifiables; +using PatchManager.Planets.Modifiables; -namespace Shoemaker.Selectables +namespace PatchManager.Planets.Selectables { public sealed class GalaxySelectable : BaseSelectable { diff --git a/Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs.meta b/Runtime/Planets/Selectables/GalaxySelectable.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Selectables/GalaxySelectable.cs.meta rename to Runtime/Planets/Selectables/GalaxySelectable.cs.meta diff --git a/Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs b/Runtime/Planets/Selectables/VolumeCloudSelectable.cs similarity index 96% rename from Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs rename to Runtime/Planets/Selectables/VolumeCloudSelectable.cs index 75c047c..9da1b0e 100644 --- a/Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs +++ b/Runtime/Planets/Selectables/VolumeCloudSelectable.cs @@ -3,10 +3,10 @@ using PatchManager.SassyPatching; using PatchManager.SassyPatching.Interfaces; using PatchManager.SassyPatching.Selectables; -using Shoemaker.Modifiables; -using Shoemaker.Overrides; +using PatchManager.Planets.Modifiables; +using PatchManager.Planets.Overrides; -namespace Shoemaker.Selectables +namespace PatchManager.Planets.Selectables { public sealed class VolumeCloudSelectable : BaseSelectable { diff --git a/Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs.meta b/Runtime/Planets/Selectables/VolumeCloudSelectable.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Selectables/VolumeCloudSelectable.cs.meta rename to Runtime/Planets/Selectables/VolumeCloudSelectable.cs.meta diff --git a/Runtime/Planets/Shoemaker/Shoemaker.csproj b/Runtime/Planets/Shoemaker.csproj similarity index 100% rename from Runtime/Planets/Shoemaker/Shoemaker.csproj rename to Runtime/Planets/Shoemaker.csproj diff --git a/Runtime/Planets/Shoemaker/Shoemaker.csproj.meta b/Runtime/Planets/Shoemaker.csproj.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Shoemaker.csproj.meta rename to Runtime/Planets/Shoemaker.csproj.meta diff --git a/Runtime/Planets/Shoemaker/Utility.meta b/Runtime/Planets/Utility.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Utility.meta rename to Runtime/Planets/Utility.meta diff --git a/Runtime/Planets/Shoemaker/Utility/Extensions.cs b/Runtime/Planets/Utility/Extensions.cs similarity index 84% rename from Runtime/Planets/Shoemaker/Utility/Extensions.cs rename to Runtime/Planets/Utility/Extensions.cs index fe3e885..784feaa 100644 --- a/Runtime/Planets/Shoemaker/Utility/Extensions.cs +++ b/Runtime/Planets/Utility/Extensions.cs @@ -1,4 +1,4 @@ -namespace Shoemaker.Utility +namespace PatchManager.Planets.Utility { public static class Extensions { diff --git a/Runtime/Planets/Shoemaker/Utility/Extensions.cs.meta b/Runtime/Planets/Utility/Extensions.cs.meta similarity index 100% rename from Runtime/Planets/Shoemaker/Utility/Extensions.cs.meta rename to Runtime/Planets/Utility/Extensions.cs.meta diff --git a/Runtime/Planets/Shoemaker/swinfo.json b/Runtime/Planets/swinfo.json similarity index 100% rename from Runtime/Planets/Shoemaker/swinfo.json rename to Runtime/Planets/swinfo.json diff --git a/Runtime/Planets/Shoemaker/swinfo.json.meta b/Runtime/Planets/swinfo.json.meta similarity index 100% rename from Runtime/Planets/Shoemaker/swinfo.json.meta rename to Runtime/Planets/swinfo.json.meta diff --git a/Runtime/Planets/Shoemaker.meta b/scripts/build-debug.bat.meta similarity index 67% rename from Runtime/Planets/Shoemaker.meta rename to scripts/build-debug.bat.meta index 5e0cfa4..480f5c2 100644 --- a/Runtime/Planets/Shoemaker.meta +++ b/scripts/build-debug.bat.meta @@ -1,6 +1,5 @@ fileFormatVersion: 2 -guid: 7e5fbfcdf3b1764499ebfbb5ea0299ad -folderAsset: yes +guid: 4a7a0e4acbccb1a4caa7fdb84a555126 DefaultImporter: externalObjects: {} userData: diff --git a/scripts/build-deploy.bat.meta b/scripts/build-deploy.bat.meta new file mode 100644 index 0000000..3a58f41 --- /dev/null +++ b/scripts/build-deploy.bat.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 87fc39df0da462e48b848880607a85e0 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/scripts/build-release.bat.meta b/scripts/build-release.bat.meta new file mode 100644 index 0000000..3a3166e --- /dev/null +++ b/scripts/build-release.bat.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 50b54e87fd268044e91485eaebb51026 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/scripts/build-run.bat.meta b/scripts/build-run.bat.meta new file mode 100644 index 0000000..28e95e9 --- /dev/null +++ b/scripts/build-run.bat.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 279e34adeb4744244b47f7bdaa8f46db +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: From 17535fdd932980097b3e690472d7df4fd579bedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bure=C5=A1?= Date: Wed, 4 Jun 2025 00:59:49 +0200 Subject: [PATCH 6/6] Deleted some unnecessary files --- .../.idea/projectSettingsUpdater.xml | 4 ++- Runtime/Planets/Directory.Build.targets.meta | 7 ----- Runtime/Planets/Patches.meta | 8 ----- Runtime/Planets/Shoemaker.csproj | 21 ------------- Runtime/Planets/Shoemaker.csproj.meta | 7 ----- Runtime/Planets/swinfo.json | 30 ------------------- Runtime/Planets/swinfo.json.meta | 7 ----- 7 files changed, 3 insertions(+), 81 deletions(-) delete mode 100644 Runtime/Planets/Directory.Build.targets.meta delete mode 100644 Runtime/Planets/Patches.meta delete mode 100644 Runtime/Planets/Shoemaker.csproj delete mode 100644 Runtime/Planets/Shoemaker.csproj.meta delete mode 100644 Runtime/Planets/swinfo.json delete mode 100644 Runtime/Planets/swinfo.json.meta diff --git a/.idea/.idea.PatchManager/.idea/projectSettingsUpdater.xml b/.idea/.idea.PatchManager/.idea/projectSettingsUpdater.xml index 4bb9f4d..ef20cb0 100644 --- a/.idea/.idea.PatchManager/.idea/projectSettingsUpdater.xml +++ b/.idea/.idea.PatchManager/.idea/projectSettingsUpdater.xml @@ -1,6 +1,8 @@ - \ No newline at end of file diff --git a/Runtime/Planets/Directory.Build.targets.meta b/Runtime/Planets/Directory.Build.targets.meta deleted file mode 100644 index bc69bbd..0000000 --- a/Runtime/Planets/Directory.Build.targets.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: d48fcc87256931e4b9f4b65a94492091 -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Planets/Patches.meta b/Runtime/Planets/Patches.meta deleted file mode 100644 index a7257fc..0000000 --- a/Runtime/Planets/Patches.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 932a8a9f89faca54f9b87d30ef3b1a9c -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Planets/Shoemaker.csproj b/Runtime/Planets/Shoemaker.csproj deleted file mode 100644 index 70f2f4a..0000000 --- a/Runtime/Planets/Shoemaker.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/Runtime/Planets/Shoemaker.csproj.meta b/Runtime/Planets/Shoemaker.csproj.meta deleted file mode 100644 index 4708c7d..0000000 --- a/Runtime/Planets/Shoemaker.csproj.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 4578e594d8f1a3a4e8b70f297108421a -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Runtime/Planets/swinfo.json b/Runtime/Planets/swinfo.json deleted file mode 100644 index 0e6d9f3..0000000 --- a/Runtime/Planets/swinfo.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "spec": "2.0", - "mod_id": "Shoemaker", - "author": "KSP2 Community", - "name": "Shoemaker", - "description": "A tool to enable planet modding for KSP2 via Patch Manager", - "source": "https://github.com/KSP2Community/Shoemaker", - "version": "0.1.0", - "version_check": "https://raw.githubusercontent.com/KSP2Community/Shoemaker/main/plugin_template/swinfo.json", - "ksp2_version": { - "min": "0.2.0", - "max": "*" - }, - "dependencies": [ - { - "id": "com.github.x606.spacewarp", - "version": { - "min": "1.8.0", - "max": "*" - } - }, - { - "id": "PatchManager", - "version": { - "min": "0.11.0", - "max": "*" - } - } - ] -} diff --git a/Runtime/Planets/swinfo.json.meta b/Runtime/Planets/swinfo.json.meta deleted file mode 100644 index df5d958..0000000 --- a/Runtime/Planets/swinfo.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 491793b9c667b7a4c9fbb09e2a4ba62b -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: