Dadido3 / noita-mapcap

A tool to capture a Noita world as a huge image
MIT License
66 stars 8 forks source link

Could we get a list of item coordinates? #9

Open danielniccoli opened 2 years ago

danielniccoli commented 2 years ago

Would it be possible to capture coordinates of items like wands during map capture?

Perhaps EntityGetInRadius could be used to output coordinates and item type (wand, spell, chest, etc.) to a file, before or after each screen capture?

Dadido3 commented 2 years ago

It's possible to gather this information, this would need some sort of deduplication, as the EntityGetInRadius areas would need to overlap. But that could be done with a set that contains already captured entities.

It would be pretty easy to write the name and coordinates for encountered entities into a file line by line. What is your usecase with this?

danielniccoli commented 2 years ago

I want to create an OpenSeaDragon map of a world and with the coordinates I could add interesting entities to the map as overlays.

Dadido3 commented 2 years ago

Ok, the mod now exports a JSON array with entities, their child entities, components, component values, and so on. It may be overkill, but you can do a lot of other stuff with this data. It also gives some insight in how the Noita engine works, which is quite interesting.

The file will be written to \mods\noita-mapcap\output\entities.json and will be about 300 MB in size. Make sure to delete entities.json when doing a new capture, as the mod will append to it. The whole export should also be proof against crashes, and noita can be restarted without loss or corruption of the JSON data.

Example of an orb entity. This is just a single line/entry in the `entities.json` file: ``` json { "filename": "data/entities/items/orbs/orb_00.xml", "transform": { "scaleY": 1, "rotation": 0, "scaleX": 1, "y": -1081.1203613281, "x": 780 }, "children": [{ "filename": "data/entities/items/orbs/orb_00.xml", "transform": { "scaleY": 1, "rotation": 0, "scaleX": 1, "y": -1092.9733886719, "x": 780 }, "children": null, "components": [{ "typeName": "InheritTransformComponent", "members": { "use_root_parent": false, "parent_hotspot_tag": "", "parent_sprite_id": -1, "always_use_immediate_parent_rotation": false, "mUpdateFrame": 4117, "rotate_based_on_x_scale": false, "only_position": false, "Transform": 0 } }, { "typeName": "ParticleEmitterComponent", "members": { "m_particle_attractor_id": -1, "m_has_emitted": false, "fade_based_on_lifetime": true, "x_vel_max": 5, "color_is_based_on_pos": false, "direction_random_deg": 0, "m_next_emit_frame": 4120, "y_vel_max": 5, "emission_chance": 100, "image_animation_raytrace_from_center": false, "m_last_emit_position": 0, "image_animation_colors_file": "", "y_pos_offset_min": 0, "image_animation_phase": 0, "set_magic_creation": false, "lifetime_max": 3, "collide_with_gas_and_fire": true, "y_vel_min": -20, "airflow_force": 0.050999999046326, "is_emitting": true, "mMaterialInventoryMax": 1024, "image_animation_use_entity_rotation": false, "image_animation_file": "", "cosmetic_force_create": true, "render_on_grid": true, "fire_cells_dont_ignite_damagemodel": false, "emitted_material_name": "spark_blue", "render_ultrabright": false, "friction": 0, "emit_cosmetic_particles": true, "offset": 0, "gravity": 0, "x_pos_offset_max": 0, "attractor_force": 0, "area_circle_sector_degrees": 360, "airflow_time": 1.0099999904633, "image_animation_speed": 1, "y_pos_offset_max": 0, "color": 0, "area_circle_radius": 0, "m_material_id": 227, "trail_gap": 0, "count_min": 15, "is_trail": false, "mExPosition": 780, "emitter_lifetime_frames": -1, "delay_frames": 0, "b2_force": 0, "emit_real_particles": false, "draw_as_long": false, "m_image_based_animation_time": 0, "airflow_scale": 0.029999999329448, "collide_with_grid": false, "image_animation_loop": true, "x_vel_min": -5, "velocity_always_away_from_center": 0, "custom_style": "NONE", "count_max": 15, "x_pos_offset_min": 0, "create_real_particles": false, "use_material_inventory": false, "image_animation_emission_probability": 1, "lifetime_min": 1, "render_back": true, "particle_single_width": true, "emission_interval_min_frames": 12, "emission_interval_max_frames": 12 } }], "name": "", "tags": ["hittable", "teleportable_NOT", "glue_NOT"] }], "components": [{ "typeName": "AudioLoopComponent", "members": { "auto_play_if_enabled": false, "m_source": 6577, "event_name": "event_cues/orb/loop", "file": "data/audio/Desktop/event_cues.bank", "m_intensity": 1, "set_speed_parameter_only_based_on_x_movement": false, "calculate_material_lowpass": false, "play_on_component_enable": false, "set_speed_parameter": false, "volume_autofade_speed": 0, "set_speed_parameter_only_based_on_y_movement": false, "m_volume": 1, "auto_play": true } }, { "typeName": "CameraBoundComponent", "members": { "freeze_on_distance_kill": true, "freeze_on_max_count_kill": true, "distance": 160000, "enabled": true, "distance_border": 20, "max_count": 20 } }, { "typeName": "HitboxComponent", "members": { "is_item": true, "aabb_max_x": 6, "is_enemy": false, "aabb_min_y": -8, "dead": false, "offset": 0, "damage_multiplier": 1, "aabb_min_x": -6, "is_player": false, "aabb_max_y": 0 } }, { "typeName": "ItemComponent", "members": { "collect_nondefault_actions": false, "camera_smooth_speed_multiplier": 1, "preferred_inventory": "QUICK", "always_use_item_name_in_ui": false, "is_identified": true, "is_frozen": false, "auto_pickup": false, "remove_default_child_actions_on_death": false, "max_child_items": 0, "stats_count_as_item_pick_up": true, "is_hittable_always": false, "remove_on_death_if_empty": false, "mIsIdentified": true, "uses_remaining": -1, "spawn_pos": 780, "mItemUid": 1152, "item_name": "$item_orb", "is_pickable": true, "npc_next_frame_pickable": 0, "permanently_attached": false, "mFramePickedUp": 0, "ui_display_description_on_pick_up_hint": false, "play_spinning_animation": false, "ui_description": "", "ui_sprite": "", "enable_orb_hacks": true, "is_consumable": false, "next_frame_pickable": 4115, "custom_pickup_string": "", "has_been_picked_by_player": false, "play_pick_sound": false, "remove_on_death": false, "is_all_spells_book": false, "play_hover_animation": false, "camera_max_distance": 50, "inventory_slot": 0, "is_stackable": false, "drinkable": true, "item_pickup_radius": 14.10000038147, "is_equipable_forced": false } }, { "typeName": "LightComponent", "members": { "offset_y": 0, "mAlpha": 1, "update_properties": false, "blinking_freq": 1, "b": 255, "offset_x": 0, "r": 255, "g": 255, "radius": 64, "fade_out_time": 0.75 } }, { "typeName": "LuaComponent", "members": { "script_collision_trigger_hit": "", "script_throw_item": "", "mLastExecutionFrame": -1, "call_init_function": false, "script_death": "", "script_inhaled_material": "", "script_enabled_changed": "", "execute_on_removed": false, "script_electricity_receiver_electrified": "", "script_source_file": "", "mModAppendsDone": false, "remove_after_executed": false, "vm_type": "SHARED_BY_MANY_COMPONENTS", "script_kick": "", "script_shot": "", "script_teleported": "", "mTimesExecuted": 0, "script_collision_trigger_timer_finished": "", "script_audio_event_dead": "", "script_damage_about_to_be_received": "", "mNextExecutionTime": 4110, "script_physics_body_modified": "", "execute_every_n_frame": 1, "script_pressure_plate_change": "", "script_material_area_checker_success": "", "script_damage_received": "", "execute_times": 0, "script_material_area_checker_failed": "", "script_portal_teleport_used": "", "script_interacting": "", "script_wand_fired": "", "script_electricity_receiver_switched": "", "enable_coroutines": false, "script_item_picked_up": "data/scripts/items/orb_pickup.lua", "execute_on_added": false } }, { "typeName": "OrbComponent", "members": { "orb_id": 0 } }, { "typeName": "SimplePhysicsComponent", "members": { "can_go_up": true, "mOldPosition": 780 } }, { "typeName": "SpriteComponent", "members": { "kill_entity_after_finished": false, "offset_y": 0, "update_transform_rotation": true, "ui_is_parent": false, "special_scale_x": 1, "emissive": false, "is_text_sprite": false, "alpha": 1, "transform_offset": 0, "rect_animation": "", "smooth_filtering": false, "special_scale_y": 1, "z_index": 20, "visible": true, "never_ragdollify_on_death": false, "offset_x": 0, "update_transform": true, "mRenderListHandle": 36063, "fog_of_war_hole": false, "next_rect_animation": "", "has_special_scale": false, "image_file": "data/items_gfx/orbs/orb_00.xml", "additive": false, "text": "", "offset_animator_offset": 0 } }, { "typeName": "SpriteComponent", "members": { "kill_entity_after_finished": false, "offset_y": 0, "update_transform_rotation": true, "ui_is_parent": false, "special_scale_x": 1, "emissive": false, "is_text_sprite": false, "alpha": 1, "transform_offset": 0, "rect_animation": "", "smooth_filtering": false, "special_scale_y": 1, "z_index": 20, "visible": true, "never_ragdollify_on_death": false, "offset_x": 0, "update_transform": true, "mRenderListHandle": 36064, "fog_of_war_hole": false, "next_rect_animation": "", "has_special_scale": false, "image_file": "data/items_gfx/orbs/orb_discovered.xml", "additive": false, "text": "", "offset_animator_offset": 0 } }, { "typeName": "SpriteComponent", "members": { "kill_entity_after_finished": false, "offset_y": 0, "update_transform_rotation": true, "ui_is_parent": false, "special_scale_x": 1, "emissive": false, "is_text_sprite": false, "alpha": 1, "transform_offset": 0, "rect_animation": "", "smooth_filtering": false, "special_scale_y": 1, "z_index": 20, "visible": true, "never_ragdollify_on_death": false, "offset_x": 0, "update_transform": true, "mRenderListHandle": 36065, "fog_of_war_hole": false, "next_rect_animation": "", "has_special_scale": false, "image_file": "data/items_gfx/orbs/orb_picked.xml", "additive": false, "text": "", "offset_animator_offset": 0 } }, { "typeName": "UIInfoComponent", "members": { "name": "$item_orb" } }, { "typeName": "VariableStorageComponent", "members": { "value_string": "SEA_LAVA", "value_int": 0, "value_bool": false, "value_float": 0, "name": "card_name" } }, { "typeName": "VelocityComponent", "members": { "mass": 0.050000000745058, "mAverageLiquidHitCount": 0, "mPrevVelocity": 0, "limit_to_max_velocity": true, "displace_liquid": true, "updates_velocity": true, "mVelocity": 0, "gravity_x": 0, "gravity_y": 400, "liquid_death_threshold": 0, "mPrevPosition": 780, "terminal_velocity": 1000, "liquid_drag": 1, "mLatestLiquidHitCount": 0, "apply_terminal_velocity": true, "affect_physics_bodies": false, "air_friction": 0.55000001192093 } }], "name": "", "tags": ["hittable", "teleportable_NOT", "polymorphable_NOT"] } ```

I will probably extend this data a bit, but the basic format will stay the same. Fell free to tell me if you need something specific.

You probably just need to look for entities with a specific filename like data/entities/items/pickup/chest_random.xml or data/entities/items/pickup/heart.xml, and then get their transformation data.