diff --git a/.gitignore b/.gitignore index d46fc38e..b9f0a467 100644 --- a/.gitignore +++ b/.gitignore @@ -49,3 +49,6 @@ obj~/ # SSH credentials, DO NOT COMMIT /scripts/credentials + +# For the Blender addon +__pycache__ diff --git a/Blender/Blender.csproj b/Blender/Blender.csproj new file mode 100644 index 00000000..c61f2790 --- /dev/null +++ b/Blender/Blender.csproj @@ -0,0 +1,31 @@ + + + + + + + + + + $(MSBuildProjectDirectory)/../Build/MapStation_Blender_Addon + $(MSBuildProjectDirectory)/../Build/MapStation_Blender_Addon.zip + + + + + + <_Assets Include="$(MSBuildProjectDirectory)/mapstation/**/*" Exclude="__pycache__" /> + + + + + + + + + diff --git a/Blender/mapstation/__init__.py b/Blender/mapstation/__init__.py new file mode 100644 index 00000000..08ebf2af --- /dev/null +++ b/Blender/mapstation/__init__.py @@ -0,0 +1,32 @@ +import importlib + +# To support auto-reload of local imports: https://blenderartists.org/t/is-reload-scripts-not-working-for-anyone-else-for-addon-development/1146804 +if "bpy" in locals(): + importlib.reload(mapstation.auto_assign_guids) + importlib.reload(mapstation.hint_ui) +else: + import mapstation.auto_assign_guids + import mapstation.hint_ui + +import bpy + +bl_info = { + "name": "MapStation", + "description": "Mapping tools for Bomb Rush Cyberfunk", + "author": "cspotcode", + "version": (1, 0), + "blender": (4, 0, 0), + "location": "", + "category": "Object" +} + +def register(): + print("Register") + mapstation.auto_assign_guids.register() + +def unregister(): + print("Unregister") + mapstation.auto_assign_guids.unregister() + +if __name__ == "__main__": + register() diff --git a/Blender/mapstation/auto_assign_guids.py b/Blender/mapstation/auto_assign_guids.py new file mode 100644 index 00000000..9f44ce02 --- /dev/null +++ b/Blender/mapstation/auto_assign_guids.py @@ -0,0 +1,33 @@ +import bpy +import uuid +guid_prop = "guid" + +def gen_guid(): + return str(uuid.uuid4()) + +def assign_guids(): + guids = set() + for obj in bpy.data.objects: + if guid_prop in obj: + guid = obj[guid_prop] + if guid in guids: + guid = gen_guid() + obj[guid_prop] = guid + else: + guid = gen_guid() + obj[guid_prop] = guid + guids.add(guid) + + # return delay so timer calls us again + return 1 + +def register(): + print("register auto_assign_guids: " + __file__) + print("hi there") + bpy.app.timers.register(assign_guids) + +def unregister(): + bpy.app.timers.unregister(assign_guids) + +if __name__ == "__main__": + register() diff --git a/Blender/mapstation/hint_ui.py b/Blender/mapstation/hint_ui.py new file mode 100644 index 00000000..9aef8c8e --- /dev/null +++ b/Blender/mapstation/hint_ui.py @@ -0,0 +1,72 @@ +import bpy + +# Define the hints array +hints = ["_Grind", "_NonStableSurface", "_Spawn"] + +class ObjectHintPanel(bpy.types.Panel): + bl_label = "BRC MapStation Hints" + bl_idname = "OBJECT_PT_hint_panel" + bl_space_type = 'VIEW_3D' + bl_region_type = 'UI' + bl_category = 'Object' + + def draw(self, context): + layout = self.layout + + obj = context.active_object + + if obj: + layout.label(text="Selected Object: " + obj.name) + layout.separator() + + for hint in hints: + # Check if the hint is present in the object name + has_hint = hint in obj.name + + # Toggle hint button + if has_hint: + layout.operator("object.remove_hint_operator", text="Remove " + hint).hint = hint + else: + layout.operator("object.add_hint_operator", text="Add " + hint).hint = hint + else: + layout.label(text="No object selected") + + +class AddHintOperator(bpy.types.Operator): + bl_idname = "object.add_hint_operator" + bl_label = "Add Hint" + + hint: bpy.props.StringProperty() + + def execute(self, context): + obj = context.active_object + obj.name += self.hint + return {'FINISHED'} + + +class RemoveHintOperator(bpy.types.Operator): + bl_idname = "object.remove_hint_operator" + bl_label = "Remove Hint" + + hint: bpy.props.StringProperty() + + def execute(self, context): + obj = context.active_object + obj.name = obj.name.replace(self.hint, "") + return {'FINISHED'} + + +def register(): + bpy.utils.register_class(ObjectHintPanel) + bpy.utils.register_class(AddHintOperator) + bpy.utils.register_class(RemoveHintOperator) + + +def unregister(): + bpy.utils.unregister_class(ObjectHintPanel) + bpy.utils.unregister_class(AddHintOperator) + bpy.utils.unregister_class(RemoveHintOperator) + + +if __name__ == "__main__": + register() diff --git a/MapStation.Editor/Assets/Maps/cspotcode.demo/VertexandCurve.blend b/MapStation.Editor/Assets/Maps/cspotcode.demo/VertexandCurve.blend new file mode 100644 index 00000000..a8c80bf6 Binary files /dev/null and b/MapStation.Editor/Assets/Maps/cspotcode.demo/VertexandCurve.blend differ diff --git a/MapStation.Editor/Assets/Maps/cspotcode.demo/VertexandCurve.blend.meta b/MapStation.Editor/Assets/Maps/cspotcode.demo/VertexandCurve.blend.meta new file mode 100644 index 00000000..8e4bedee --- /dev/null +++ b/MapStation.Editor/Assets/Maps/cspotcode.demo/VertexandCurve.blend.meta @@ -0,0 +1,106 @@ +fileFormatVersion: 2 +guid: 0d1037da6b6fb6747a23937f64788ffa +ModelImporter: + serializedVersion: 21300 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 1 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 1 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: 0 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/MapStation.Editor/Assets/Maps/cspotcode.demo/newblend.blend b/MapStation.Editor/Assets/Maps/cspotcode.demo/newblend.blend new file mode 100644 index 00000000..fb99a8ad Binary files /dev/null and b/MapStation.Editor/Assets/Maps/cspotcode.demo/newblend.blend differ diff --git a/MapStation.Editor/Assets/Maps/cspotcode.demo/newblend.blend.meta b/MapStation.Editor/Assets/Maps/cspotcode.demo/newblend.blend.meta new file mode 100644 index 00000000..35659246 --- /dev/null +++ b/MapStation.Editor/Assets/Maps/cspotcode.demo/newblend.blend.meta @@ -0,0 +1,106 @@ +fileFormatVersion: 2 +guid: a5573d021026a1f43a5b46f85deafa84 +ModelImporter: + serializedVersion: 21300 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 1 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 1 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 1 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 1 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 1 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: 0 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/MapStation.Editor/Assets/Maps/cspotcode.demo/spline-from-blender.blend b/MapStation.Editor/Assets/Maps/cspotcode.demo/spline-from-blender.blend new file mode 100644 index 00000000..d0cc043a Binary files /dev/null and b/MapStation.Editor/Assets/Maps/cspotcode.demo/spline-from-blender.blend differ diff --git a/MapStation.Editor/Assets/Maps/cspotcode.demo/spline-from-blender.blend.meta b/MapStation.Editor/Assets/Maps/cspotcode.demo/spline-from-blender.blend.meta new file mode 100644 index 00000000..f638d73f --- /dev/null +++ b/MapStation.Editor/Assets/Maps/cspotcode.demo/spline-from-blender.blend.meta @@ -0,0 +1,106 @@ +fileFormatVersion: 2 +guid: 04f0a475453fe684ab32c717251ff5e4 +ModelImporter: + serializedVersion: 21300 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 1 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/MapStation.Tools/Editor/ImporterThing.cs b/MapStation.Tools/Editor/ImporterThing.cs new file mode 100644 index 00000000..2d2e0784 --- /dev/null +++ b/MapStation.Tools/Editor/ImporterThing.cs @@ -0,0 +1,39 @@ +using System.IO; +using Reptile; +using UnityEditor; +using UnityEngine; + +class CustomImportProcessor : AssetPostprocessor { + + // void OnPostprocessGameObjectWithUserProperties(GameObject go, string[] names, System.Object[] values) { + // ModelImporter importer = (ModelImporter)assetImporter; + // var asset_name = Path.GetFileName(importer.assetPath); + // Debug.LogFormat("OnPostprocessGameObjectWithUserProperties(go = {0}) asset = {1} path = {2}", go.name, asset_name, importer.assetPath); + // Vector3 vec3 = Vector3.zero; + // for (int i = 0; i < names.Length; i++) { + // var name = names[i]; + // var val = values[i]; + // Debug.Log($"{name}={val}"); + // } + // var teleport = go.AddComponent(); + // teleport.teleportTo = go.transform; + // } + // + // void OnPostprocessMeshHierarchy(GameObject go) { + // Debug.Log("OnPostprocessMeshHierarchy"); + // var teleport = go.AddComponent(); + // teleport.teleportTo = go.transform; + // + // } + // void OnPostprocessModel(GameObject go) { + // Debug.Log("OnPostprocessModel"); + // var teleport = go.AddComponent(); + // + // } + // void OnPostprocessPrefab(GameObject go) { + // Debug.Log("OnPostprocessPrefab"); + // var teleport = go.AddComponent(); + // teleport.teleportTo = go.transform; + // + // } +} diff --git a/MapStation.Tools/Editor/ImporterThing.cs.meta b/MapStation.Tools/Editor/ImporterThing.cs.meta new file mode 100644 index 00000000..bc965c5a --- /dev/null +++ b/MapStation.Tools/Editor/ImporterThing.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 50aef77b27197814fad1693af611252b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/MapStation.sln b/MapStation.sln index 6c47e61a..b148e76a 100644 --- a/MapStation.sln +++ b/MapStation.sln @@ -18,6 +18,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapStation.Tools", "MapStat EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SlopCrewClient", "libs\SlopCrewClient\SlopCrewClient\SlopCrewClient.csproj", "{A148FFDA-2617-45B5-AD09-6E1369617520}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Blender", "Blender\Blender.csproj", "{AB57FECC-D0A5-4E4D-BA0F-BB2860D9033D}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -52,6 +54,8 @@ Global {A148FFDA-2617-45B5-AD09-6E1369617520}.Debug|Any CPU.Build.0 = Debug|Any CPU {A148FFDA-2617-45B5-AD09-6E1369617520}.Release|Any CPU.ActiveCfg = Release|Any CPU {A148FFDA-2617-45B5-AD09-6E1369617520}.Release|Any CPU.Build.0 = Release|Any CPU + {AB57FECC-D0A5-4E4D-BA0F-BB2860D9033D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {AB57FECC-D0A5-4E4D-BA0F-BB2860D9033D}.Debug|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE