<commit_before>#include "lua_script_system.h"
#include "engine/array.h"
#include "engine/base_proxy_allocator.h"
#include "engine/binary_array.h"
#include "engine/blob.h"
#include "engine/crc32.h"
#include "engine/fs/file_system.h"
#include "engine/iallocator.h"
#include "engine/json_serializer.h"
#include "engine/log.h"
#include "engine/lua_wrapper.h"
#include "engine/path_utils.h"
#include "engine/resource_manager.h"
#include "engine/debug/debug.h"
#include "engine/engine.h"
#include "engine/property_register.h"
#include "engine/property_descriptor.h"
#include "engine/iplugin.h"
#include "lua_script/lua_script_manager.h"
#include "engine/plugin_manager.h"
#include "engine/universe/universe.h"


namespace Lumix
{


	enum class LuaScriptVersion
	{
		MULTIPLE_SCRIPTS,
		REFACTOR,

		LATEST
	};
	
	
	static const ComponentType LUA_SCRIPT_TYPE = PropertyRegister::getComponentType("lua_script");
	static const ResourceType LUA_SCRIPT_RESOURCE_TYPE("lua_script");


	class LuaScriptSystemImpl : public IPlugin
	{
	public:
		explicit LuaScriptSystemImpl(Engine& engine);
		virtual ~LuaScriptSystemImpl();

		IScene* createScene(Universe& universe) override;
		void destroyScene(IScene* scene) override;
		const char* getName() const override { return "lua_script"; }
		LuaScriptManager& getScriptManager() { return m_script_manager; }

		Engine& m_engine;
		Debug::Allocator m_allocator;
		LuaScriptManager m_script_manager;
	};


	struct LuaScriptSceneImpl : public LuaScriptScene
	{
		struct TimerData
		{
			float time;
			lua_State* state;
			int func;
		};

		struct UpdateData
		{
			LuaScript* script;
			lua_State* state;
			int environment;
		};


		struct ScriptInstance
		{
			explicit ScriptInstance(IAllocator& allocator)
				: m_properties(allocator)
				, m_script(nullptr)
				, m_state(nullptr)
				, m_environment(-1)
				, m_thread_ref(-1)
			{
			}

			LuaScript* m_script;
			lua_State* m_state;
			int m_environment;
			int m_thread_ref;
			Array<Property> m_properties;
		};


		struct ScriptComponent
		{
			ScriptComponent(LuaScriptSceneImpl& scene, IAllocator& allocator)
				: m_scripts(allocator)
				, m_scene(scene)
				, m_entity(INVALID_ENTITY)
			{
			}


			static int getProperty(ScriptInstance& inst, uint32 hash)
			{
				for(int i = 0, c = inst.m_properties.size(); i < c; ++i)
				{
					if (inst.m_properties[i].name_hash == hash) return i;
				}
				return -1;
			}


			void detectProperties(ScriptInstance& inst)
			{
				static const uint32 INDEX_HASH = crc32("__index");
				static const uint32 THIS_HASH = crc32("this");
				lua_State* L = inst.m_state;
				bool is_env_valid = lua_rawgeti(L, LUA_REGISTRYINDEX, inst.m_environment) == LUA_TTABLE;
				ASSERT(is_env_valid);
				lua_pushnil(L);
				auto& allocator = m_scene.m_system.m_allocator;
				BinaryArray valid_properties(m_scene.m_system.m_engine.getLIFOAllocator());
				valid_properties.resize(inst.m_properties.size());
				setMemory(valid_properties.getRaw(), 0, valid_properties.size() >> 3);

				while (lua_next(L, -2))
				{
					if (lua_type(L, -1) != LUA_TFUNCTION)
					{
						const char* name = lua_tostring(L, -2);
						uint32 hash = crc32(name);
						if (m_scene.m_property_names.find(hash) < 0)
						{
							m_scene.m_property_names.emplace(hash, name, allocator);
						}
						if (hash != INDEX_HASH && hash != THIS_HASH)
						{
							int prop_index = getProperty(inst, hash);
							if (prop_index >= 0)
							{
								valid_properties[prop_index] = true;
								Property& existing_prop = inst.m_properties[prop_index];
								if (existing_prop.type == Property::ANY)
								{
									switch (lua_type(inst.m_state, -1))
									{
										case LUA_TBOOLEAN: existing_prop.type = Property::BOOLEAN; break;
										default: existing_prop.type = Property::FLOAT;
									}
								}
								m_scene.applyProperty(inst, existing_prop, existing_prop.stored_value.c_str());
							}
							else
							{
								auto& prop = inst.m_properties.emplace(allocator);
								valid_properties.push(true);
								switch (lua_type(inst.m_state, -1))
								{
									case LUA_TBOOLEAN: prop.type = Property::BOOLEAN; break;
									default: prop.type = Property::FLOAT;
								}
								prop.name_hash = hash;
							}
						}
					}
					lua_pop(L, 1);
				}
				for (int i = inst.m_properties.size() - 1; i >= 0; --i)
				{
					if (valid_properties[i]) continue;
					inst.m_properties.eraseFast(i);
				}
			}


			void onScriptLoaded(Resource::State, Resource::State, Resource&)
			{
				lua_State* L = m_scene.m_system.m_engine.getState();
				for (auto& script : m_scripts)
				{
					if (!script.m_script) continue;
					if (!script.m_script->isReady()) continue;

					bool is_reload = true;
					if (!script.m_state)
					{
						is_reload = false;
						script.m_environment = -1;

						script.m_state = lua_newthread(L);
						lua_pushvalue(L, -1);
						script.m_thread_ref = luaL_ref(L, LUA_REGISTRYINDEX);
						lua_pop(L, 1);
						lua_newtable(script.m_state);
						// reference environment
						lua_pushvalue(script.m_state, -1);
						script.m_environment = luaL_ref(script.m_state, LUA_REGISTRYINDEX);

						// environment's metatable & __index
						lua_pushvalue(script.m_state, -1);
						lua_setmetatable(script.m_state, -2);<commit_msg>reload only script which is really reloaded<commit_after>#include "lua_script_system.h"
#include "engine/array.h"
#include "engine/base_proxy_allocator.h"
#include "engine/binary_array.h"
#include "engine/blob.h"
#include "engine/crc32.h"
#include "engine/fs/file_system.h"
#include "engine/iallocator.h"
#include "engine/json_serializer.h"
#include "engine/log.h"
#include "engine/lua_wrapper.h"
#include "engine/path_utils.h"
#include "engine/resource_manager.h"
#include "engine/debug/debug.h"
#include "engine/engine.h"
#include "engine/property_register.h"
#include "engine/property_descriptor.h"
#include "engine/iplugin.h"
#include "lua_script/lua_script_manager.h"
#include "engine/plugin_manager.h"
#include "engine/universe/universe.h"


namespace Lumix
{


	enum class LuaScriptVersion
	{
		MULTIPLE_SCRIPTS,
		REFACTOR,

		LATEST
	};
	
	
	static const ComponentType LUA_SCRIPT_TYPE = PropertyRegister::getComponentType("lua_script");
	static const ResourceType LUA_SCRIPT_RESOURCE_TYPE("lua_script");


	class LuaScriptSystemImpl : public IPlugin
	{
	public:
		explicit LuaScriptSystemImpl(Engine& engine);
		virtual ~LuaScriptSystemImpl();

		IScene* createScene(Universe& universe) override;
		void destroyScene(IScene* scene) override;
		const char* getName() const override { return "lua_script"; }
		LuaScriptManager& getScriptManager() { return m_script_manager; }

		Engine& m_engine;
		Debug::Allocator m_allocator;
		LuaScriptManager m_script_manager;
	};


	struct LuaScriptSceneImpl : public LuaScriptScene
	{
		struct TimerData
		{
			float time;
			lua_State* state;
			int func;
		};

		struct UpdateData
		{
			LuaScript* script;
			lua_State* state;
			int environment;
		};


		struct ScriptInstance
		{
			explicit ScriptInstance(IAllocator& allocator)
				: m_properties(allocator)
				, m_script(nullptr)
				, m_state(nullptr)
				, m_environment(-1)
				, m_thread_ref(-1)
			{
			}

			LuaScript* m_script;
			lua_State* m_state;
			int m_environment;
			int m_thread_ref;
			Array<Property> m_properties;
		};


		struct ScriptComponent
		{
			ScriptComponent(LuaScriptSceneImpl& scene, IAllocator& allocator)
				: m_scripts(allocator)
				, m_scene(scene)
				, m_entity(INVALID_ENTITY)
			{
			}


			static int getProperty(ScriptInstance& inst, uint32 hash)
			{
				for(int i = 0, c = inst.m_properties.size(); i < c; ++i)
				{
					if (inst.m_properties[i].name_hash == hash) return i;
				}
				return -1;
			}


			void detectProperties(ScriptInstance& inst)
			{
				static const uint32 INDEX_HASH = crc32("__index");
				static const uint32 THIS_HASH = crc32("this");
				lua_State* L = inst.m_state;
				bool is_env_valid = lua_rawgeti(L, LUA_REGISTRYINDEX, inst.m_environment) == LUA_TTABLE;
				ASSERT(is_env_valid);
				lua_pushnil(L);
				auto& allocator = m_scene.m_system.m_allocator;
				BinaryArray valid_properties(m_scene.m_system.m_engine.getLIFOAllocator());
				valid_properties.resize(inst.m_properties.size());
				setMemory(valid_properties.getRaw(), 0, valid_properties.size() >> 3);

				while (lua_next(L, -2))
				{
					if (lua_type(L, -1) != LUA_TFUNCTION)
					{
						const char* name = lua_tostring(L, -2);
						uint32 hash = crc32(name);
						if (m_scene.m_property_names.find(hash) < 0)
						{
							m_scene.m_property_names.emplace(hash, name, allocator);
						}
						if (hash != INDEX_HASH && hash != THIS_HASH)
						{
							int prop_index = getProperty(inst, hash);
							if (prop_index >= 0)
							{
								valid_properties[prop_index] = true;
								Property& existing_prop = inst.m_properties[prop_index];
								if (existing_prop.type == Property::ANY)
								{
									switch (lua_type(inst.m_state, -1))
									{
										case LUA_TBOOLEAN: existing_prop.type = Property::BOOLEAN; break;
										default: existing_prop.type = Property::FLOAT;
									}
								}
								m_scene.applyProperty(inst, existing_prop, existing_prop.stored_value.c_str());
							}
							else
							{
								auto& prop = inst.m_properties.emplace(allocator);
								valid_properties.push(true);
								switch (lua_type(inst.m_state, -1))
								{
									case LUA_TBOOLEAN: prop.type = Property::BOOLEAN; break;
									default: prop.type = Property::FLOAT;
								}
								prop.name_hash = hash;
							}
						}
					}
					lua_pop(L, 1);
				}
				for (int i = inst.m_properties.size() - 1; i >= 0; --i)
				{
					if (valid_properties[i]) continue;
					inst.m_properties.eraseFast(i);
				}
			}


			void onScriptLoaded(Resource::State, Resource::State, Resource& resource)
			{
				lua_State* L = m_scene.m_system.m_engine.getState();
				for (auto& script : m_scripts)
				{
					if (!script.m_script) continue;
					if (!script.m_script->isReady()) continue;
					if (script.m_script != &resource) continue;

					bool is_reload = true;
					if (!script.m_state)
					{
						is_reload = false;
						script.m_environment = -1;

						script.m_state = lua_newthread(L);
						lua_pushvalue(L, -1);
						script.m_thread_ref = luaL_ref(L, LUA_REGISTRYINDEX);
						lua_pop(L, 1);
						lua_newtable(script.m_state);
						// reference environment
						lua_pushvalue(script.m_state, -1);
						script.m_environment = luaL_ref(script.m_state, LUA_REGISTRYINDEX);

						// environment's metatable & __index
						lua_pushvalue(script.m_state, -1);
						lua_setmetatable(script.m_state, -2);
{'fraction_non_alphanumeric': 0.1188516925378717, 'fraction_numerical': 0.007106788853562746, 'mean_word_length': 3.2558694787107045, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1349821', 'n_tokens_mistral': 4844, 'n_tokens_neox': 3729, 'n_words': 680}