Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Could we get a list of item coordinates? #9

Open
danielniccoli opened this issue Jul 16, 2022 · 3 comments
Open

Could we get a list of item coordinates? #9

danielniccoli opened this issue Jul 16, 2022 · 3 comments

Comments

@danielniccoli
Copy link

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
Copy link
Owner

Dadido3 commented Jul 16, 2022

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
Copy link
Author

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 added a commit that referenced this issue Jul 17, 2022
Dadido3 added a commit that referenced this issue Jul 17, 2022
- Add JSON library that can marshal Noita entities and components
- Add Noita API wrapper that exposes entities and components as objects
- Change how the entities file is written, to support lightweight and crash proof appending of JSON data

#9
Dadido3 added a commit that referenced this issue Jul 18, 2022
- Add JSON marshal "interface" that objects can implement
- Fix EmmyLua annotation
- Move JSON marshaler into noita-api.lua

#9
Dadido3 added a commit that referenced this issue Jul 18, 2022
@Dadido3
Copy link
Owner

Dadido3 commented Jul 18, 2022

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:
{
	"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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants