Initial work on LUA scripting.

This LUA scripting implementation uses the sol header only C++ wrapper for the native LUA libraries.

The API does not follow the original LU scripting. Each instance of a script is in its own LUA-State, and has 'self' as a global. There are hooks to all the implemented CppScript methods, as well as a subset of the entity functionallity. Has to be expanded upon.

This is local work which has been sitting for awhile; thought someone might like to take a look at it.
This commit is contained in:
wincent 2022-04-13 19:51:14 +02:00
parent a0a9936e47
commit 5f689104af
18 changed files with 31747 additions and 1 deletions

View File

@ -209,6 +209,14 @@ include_directories(${PROJECT_SOURCE_DIR}/thirdparty/cpplinq/)
include_directories(${PROJECT_SOURCE_DIR}/dNet/)
include_directories(${PROJECT_SOURCE_DIR}/dScripts/)
# Link dGame to LUA
if(__include_lua__)
find_package(Lua REQUIRED)
include_directories(/usr/include ${LUA_INCLUDE_DIR})
include_directories(${PROJECT_SOURCE_DIR}/dLua/)
endif(UNIX)
# Default to linking to libmysql
set(MYSQL_LIB mysql)
if(WIN32)
@ -355,6 +363,19 @@ ${PROJECT_SOURCE_DIR}/dGame/dUtilities/*.cpp
${PROJECT_SOURCE_DIR}/dScripts/*.cpp
)
# If we are including LUA, include the dLua files in dGame
if(__include_lua__)
file(
GLOB SOURCES_DLUA
LIST_DIRECTORIES false
RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}"
${PROJECT_SOURCE_DIR}/dLua/*.cpp
)
# Append the dLua files to the dGame files
set(SOURCES_DGAME ${SOURCES_DGAME} ${SOURCES_DLUA})
endif(__include_lua__)
# Source Code for dZoneManager
file(
GLOB SOURCES_DZM
@ -466,6 +487,15 @@ target_link_libraries(ChatServer pthread)
target_link_libraries(ChatServer dl)
endif(UNIX)
# Link dGame to LUA
if(__include_lua__)
find_package(Lua REQUIRED)
target_link_libraries(dGame ${LUA_LIBRARIES})
message(STATUS "Linking dGame to LUA " ${LUA_LIBRARIES})
endif(UNIX)
# Compiler flags:
# Disabled deprecated warnings as the MySQL includes have deprecated code in them.
# Disabled misleading indentation as DL_LinkedList from RakNet has a weird indent.

View File

@ -63,6 +63,12 @@
#include "GameConfig.h"
#include "ScriptedActivityComponent.h"
#if __include_lua__ == 1
#include "LuaScript.h"
#include "ScriptComponent.h"
#include <filesystem>
#endif
void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entity* entity, const SystemAddress& sysAddr) {
std::string chatCommand;
std::vector<std::string> args;
@ -614,6 +620,78 @@ void SlashCommandHandler::HandleChatCommand(const std::u16string& command, Entit
return;
}
#if __include_lua__ == 1
if (chatCommand == "lua" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER && args.size() >= 1) {
std::string input = "";
// If the first argument is "load", load the file
bool isFile = false;
if (args[0] == "load") {
isFile = true;
}
// Join the args
for (size_t i = 0; i < args.size(); i++) {
if (i == 0 && isFile) continue;
input += args[i] + " ";
}
// If isFile is true, load the file
if (isFile) {
// Trim last space
input.pop_back();
std::string path = input;
std::ifstream infile(path);
std::stringstream buffer;
if (infile.is_open()) {
std::string line;
while (std::getline(infile, line)) {
buffer << line << "\n";
}
}
else {
ChatPackets::SendSystemMessage(sysAddr, u"Could not open file " + GeneralUtils::ASCIIToUTF16(path));
return;
}
input = buffer.str();
infile.close();
}
LuaScript* lua = new LuaScript(LuaTerminateBehavior::ResetScriptAndDelete);
ScriptComponent* script = entity->GetComponent<ScriptComponent>();
if (script == nullptr) {
script = new ScriptComponent(entity, false);
entity->AddComponent(ScriptComponent::ComponentType, script);
}
script->SetScript(lua);
lua->SetEntity(entity);
// Run the code, and print any errors
try {
lua->Script(input);
}
// Catch sol::error
catch (const sol::error& e) {
ChatPackets::SendSystemMessage(sysAddr, GeneralUtils::ASCIIToUTF16(e.what()));
}
// Catch *any* error
catch (...) {
ChatPackets::SendSystemMessage(sysAddr, u"Unknown error!");
}
}
#endif
if (chatCommand == "addmission" && entity->GetGMLevel() >= GAME_MASTER_LEVEL_DEVELOPER) {
if (args.size() == 0) return;

135
dLua/LuaScript.cpp Normal file
View File

@ -0,0 +1,135 @@
#include "LuaScript.h"
#include "Entity.h"
#include "lCommonTypes.h"
#include "lEntity.h"
#include "ChatPackets.h"
#include "CppScripts.h"
#include "ScriptComponent.h"
#include "Game.h"
#include "dLogger.h"
LuaScript::LuaScript(LuaTerminateBehavior terminateBehavior)
{
m_TerminateBehavior = terminateBehavior;
m_Hooks = 0;
m_Terminating = false;
m_State = sol::state();
m_State.open_libraries(sol::lib::base, sol::lib::package);
lCommonTypes::RegisterClass(this);
lEntity::RegisterClass(this);
// Register a function to print to log
m_State.set_function("print", [](const std::string& message) {
Game::logger->Log("dLua", "%s\n", message.c_str());
});
// Register a function to terminate the script
m_State.set_function("terminate", [this]() {
m_Terminating = true;
auto* scriptComponent = GetEntity()->GetComponent<ScriptComponent>();
if (scriptComponent == nullptr || scriptComponent->GetScript() != this)
{
return;
}
switch (m_TerminateBehavior)
{
case LuaTerminateBehavior::None:
break;
case LuaTerminateBehavior::ResetScript:
case LuaTerminateBehavior::ResetScriptAndDelete:
scriptComponent->SetScript(CppScripts::GetInvalidScript());
break;
}
});
// Register a function to add a callback timer
m_State.set_function("addCallbackTimer", [this](float seconds, sol::function callback) {
AddCallbackTimer(seconds, callback);
});
}
sol::state& LuaScript::GetState()
{
return m_State;
}
void LuaScript::Script(const std::string& script)
{
m_State.script(script);
}
void LuaScript::SetEntity(Entity* entity)
{
m_State["self"] = lEntity(entity->GetObjectID());
}
Entity* LuaScript::GetEntity()
{
lEntity entity = m_State["self"];
return dLua::GetEntityOrThrow(entity.id);
}
void LuaScript::AddCallbackTimer(float seconds, sol::function callback) {
if (m_Terminating) {
Game::logger->Log("LuaScript", "Script is terminating, ignoring addCallbackTimer\n");
return;
}
m_Hooks++;
GetEntity()->AddCallbackTimer(seconds, [this, callback]() {
m_Hooks--;
CheckHooks();
if (m_Terminating) {
Game::logger->Log("LuaScript", "Script is terminating, ignoring callback\n");
return;
}
try {
callback();
}
catch (sol::error& e) {
Game::logger->Log("LuaScript", "Error in callback: %s\n", e.what());
}
});
}
void LuaScript::CheckHooks()
{
if (m_Hooks != 0 || m_AttemptingToFinalize || !m_Terminating) {
return;
}
m_AttemptingToFinalize = true;
// Attempt to finalize the script in 1 second
GetEntity()->AddCallbackTimer(1.0f, [this]() {
AttemptToFinalize();
});
}
void LuaScript::AttemptToFinalize()
{
if (m_Hooks != 0) {
m_AttemptingToFinalize = false;
return;
}
switch (m_TerminateBehavior)
{
case LuaTerminateBehavior::ResetScriptAndDelete:
Game::logger->Log("LuaScript", "Deleting script\n");
delete this;
break;
}
}

426
dLua/LuaScript.h Normal file
View File

@ -0,0 +1,426 @@
#include "dLua.h"
#include "CppScripts.h"
#include "Game.h"
#include "dLogger.h"
#include "LuaTerminateBehavior.h"
#include "lEntity.h"
class Entity;
class LuaScript : public CppScripts::Script
{
private:
sol::state m_State;
LuaTerminateBehavior m_TerminateBehavior;
int32_t m_Hooks;
bool m_Terminating;
bool m_AttemptingToFinalize;
void CheckHooks();
void AttemptToFinalize();
public:
LuaScript(LuaTerminateBehavior terminateBehavior);
sol::state& GetState();
void Script(const std::string& script);
void SetEntity(Entity* entity);
Entity* GetEntity();
/**
* Add a callback timer.
*/
void AddCallbackTimer(float seconds, sol::function callback);
template <typename F, typename ...Types>
void Invoke(F function, Types... args)
{
sol::function func = m_State[function];
if (!func.valid())
{
return;
}
func(std::forward<Types>(args)...);
}
// ======================================================================
// CppScripts::Script overrides
// ======================================================================
/**
* Invoked one frame after the script is loaded.
*
* Equivalent to 'function onStartup(self)'
*/
void OnStartup(Entity* self) override {
Invoke("onStartup");
}
/**
* Invoked upon an entity entering the phantom collider on self.
*
* Equivalent to 'function onCollisionPhantom(self, msg)'
*/
void OnCollisionPhantom(Entity* self, Entity* target) override {
Invoke("onCollisionPhantom", lEntity(target));
}
/**
* Invoked when a player accepted a mission.
*
* Equivalent to 'function onMissionDialogueOK(self, msg)'
*/
void OnMissionDialogueOK(Entity* self, Entity* target, int missionID, MissionState missionState) override {
Invoke("onMissionDialogueOK", lEntity(target), missionID, (int32_t) missionState);
}
/**
* Invoked when the client or the server invoked an event server-side.
*
* Equivalent to 'function onFireEventServerSide(self, msg)'
*/
void OnFireEventServerSide(Entity *self, Entity *sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override {
Invoke("onFireEventServerSide", lEntity(sender), args, param1, param2, param3);
}
/**
* Invoked upon sending a object notification.
*
* Equivalent to 'function onNotifyObject(self, msg)'
*/
void OnNotifyObject(Entity *self, Entity *sender, const std::string& name, int32_t param1 = 0, int32_t param2 = 0) override {
Invoke("onNotifyObject", lEntity(sender), name, param1, param2);
}
/**
* Invoked upon a player exiting the modular build minigame.
*
* Equivalent to 'function onModularBuildExit(self, msg)'
*/
void OnModularBuildExit(Entity* self, Entity* player, bool bCompleted, std::vector<LOT> modules) override {
Invoke("onModularBuildExit", lEntity(player), bCompleted, modules);
}
/**
* Invoked when a player has loaded into the zone.
*
* Equivalent to 'function onPlayerLoaded(self, msg)'
*/
void OnPlayerLoaded(Entity* self, Entity* player) override {
Invoke("onPlayerLoaded", lEntity(player));
}
/**
* Invoked when a player has died.
*
* Equivalent to 'function onPlayerDied(self, msg)'
*/
void OnPlayerDied(Entity* self, Entity* player) override {
Invoke("onPlayerDied", lEntity(player));
}
/**
* Invoked when a player has resurrected.
*
* Equivalent to 'function onPlayerResurrected(self, msg)'
*/
void OnPlayerResurrected(Entity* self, Entity* player) override {
Invoke("onPlayerResurrected", lEntity(player));
}
/**
* Invoked when a player has left the zone.
*
* Equivalent to 'function onPlayerExit(self, msg)'
*/
void OnPlayerExit(Entity* self, Entity* player) override {
Invoke("onPlayerExit", lEntity(player));
}
/**
* Invoked when a player has interacted with the proximity collider on self.
*
* Equivalent to 'function onProximityUpdate(self, msg)'
*
* @param name The name of the proximity collider recviving an interaction.
* @param status "ENTER" if a player has entered the proximity collider; "LEAVE" if a player has left the proximity collider
*/
void OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) override {
Invoke("onProximityUpdate", lEntity(entering), name, status);
}
/**
* Invoked when a timer on self has expired.
*
* Equivalent to 'function onTimerDone(self, msg)'
*/
void OnTimerDone(Entity* self, std::string timerName) override {
Invoke("onTimerDone", timerName);
}
/**
* Invoked when a player interactions with self.
*
* Equivalent to 'function onUse(self, msg)'
*/
void OnUse(Entity* self, Entity* user) override {
Invoke("onUse", lEntity(user));
}
/**
* Invoked when self has died.
*
* Equivalent to 'function onDie(self, msg)'
*/
void OnDie(Entity* self, Entity* killer) override {
Invoke("onDie", lEntity(killer));
}
/**
* Invoked when self has received a hit.
*
* Equivalent to 'function onHit(self, msg)'
*/
void OnHit(Entity* self, Entity* attacker) override {
Invoke("onHit", lEntity(attacker));
}
/**
* Invoked when self has received an emote from a player.
*
* Equivalent to 'function onEmoteReceived(self, msg)'
*/
void OnEmoteReceived(Entity* self, int32_t emote, Entity* target) override {
Invoke("onEmoteReceived", emote, lEntity(target));
}
/**
* Invoked when a player has started building this quickbuild.
*
* Equivalent to 'function onRebuildStart(self, msg)'
*/
void OnRebuildStart(Entity* self, Entity* target) override {
Invoke("onRebuildStart", lEntity(target));
}
/**
* Invoked when this quickbuild has changed state.
*
* Equivalent to 'function onRebuildNotifyState(self, msg)'
*/
void OnRebuildNotifyState(Entity* self, eRebuildState state) override {
Invoke("onRebuildNotifyState", (int32_t) state);
}
/**
* Invoked when this quickbuild has been completed.
*
* Equivalent to 'function onRebuildComplete(self, msg)'
*/
void OnRebuildComplete(Entity* self, Entity* target) override {
Invoke("onRebuildComplete", lEntity(target));
}
/**
* Invoked when self has received either a hit or heal.
*
* Equivalent to 'function onHitOrHealResult(self, msg)'
*/
void OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) override {
Invoke("onHitOrHealResult", lEntity(attacker), damage);
}
/**
* Invoked when a player has responsed to a mission.
*
* Equivalent to 'function onRespondToMission(self, msg)'
*/
void OnRespondToMission(Entity* self, int missionID, Entity* player, int reward) override {
Invoke("onRespondToMission", missionID, lEntity(player), reward);
}
/**
* Invoked once per frame.
*
* No LUA eqivalent.
*/
void OnUpdate(Entity* self) override {
Invoke("onUpdate");
}
/**
* Invoked when this property has been rented.
*
* Equivalent to 'function onZonePropertyRented(self, msg)'
*/
void OnZonePropertyRented(Entity* self, Entity* renter) override {
Invoke("onZonePropertyRented", lEntity(renter));
}
/**
* Invoked when a player has begun to edit this property.
*
* Equivalent to 'function onZonePropertyEditBegin(self, msg)'
*/
void OnZonePropertyEditBegin(Entity* self) override {
Invoke("onZonePropertyEditBegin");
}
/**
* Invoked when a player has concluded editing this property.
*
* Equivalent to 'function onZonePropertyEditEnd(self, msg)'
*/
void OnZonePropertyEditEnd(Entity* self) override {
Invoke("onZonePropertyEditEnd");
}
/**
* Invoked when a player has equipped a model while editing this property.
*
* Equivalent to 'function onZonePropertyModelEquipped(self, msg)'
*/
void OnZonePropertyModelEquipped(Entity* self) override {
Invoke("onZonePropertyModelEquipped");
}
/**
* Invoked when a player has placed a model while editing this property.
*
* Equivalent to 'function onZonePropertyModelPlaced(self, msg)'
*/
void OnZonePropertyModelPlaced(Entity* self, Entity* player) override {
Invoke("onZonePropertyModelPlaced", lEntity(player));
}
/**
* Invoked when a player has picked up a model while editing this property.
*
* Equivalent to 'function onZonePropertyModelPickedUp(self, msg)'
*/
void OnZonePropertyModelPickedUp(Entity* self, Entity* player) override {
Invoke("onZonePropertyModelPickedUp", lEntity(player));
}
/**
* Invoked when a player removed a model while editing this property.
*
* Equivalent to 'function onZonePropertyModelRemoved(self, msg)'
*/
void OnZonePropertyModelRemoved(Entity* self, Entity* player) override {
Invoke("onZonePropertyModelRemoved", lEntity(player));
}
/**
* Invoked when a player removed a model while holding it when editing this property.
*
* Equivalent to 'function onZonePropertyModelRemoved(self, msg)'
*/
void OnZonePropertyModelRemovedWhileEquipped(Entity* self, Entity* player) override {
Invoke("onZonePropertyModelRemovedWhileEquipped", lEntity(player));
}
/**
* Invoked when a player rotated a model while editing this property.
*
* Equivalent to 'function onZonePropertyModelRotated(self, msg)'
*/
void OnZonePropertyModelRotated(Entity* self, Entity* player) override {
Invoke("onZonePropertyModelRotated", lEntity(player));
}
/**
* Invoked when the pet taming minigame encounted an event.
*
* Equivalent to 'function onNotifyPetTamingMinigame(self, msg)'
*/
void OnNotifyPetTamingMinigame(Entity* self, Entity* tamer, eNotifyType type) override {
Invoke("onNotifyPetTamingMinigame", lEntity(tamer), (int32_t) type);
}
/**
* Invoked when a player responded to a message box.
*
* Equivalent to 'function onMessageBoxResponse(self, msg)'
*/
void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override {
Invoke("onMessageBoxResponse", lEntity(sender), button, GeneralUtils::UTF16ToWTF8(identifier), GeneralUtils::UTF16ToWTF8(userData));
}
/**
* Invoked when a player responded to a choice box.
*
* Equivalent to 'function onChoiceBoxResponse(self, msg)'
*/
void OnChoiceBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier) override {
Invoke("onChoiceBoxResponse", lEntity(sender), button, GeneralUtils::UTF16ToWTF8(buttonIdentifier), GeneralUtils::UTF16ToWTF8(identifier));
}
/**
* Invoked when self arrived at a moving platform waypoint.
*
* Equivalent to 'function onWaypointReached(self, msg)'
*/
void OnWaypointReached(Entity* self, uint32_t waypointIndex) override {
Invoke("onWaypointReached", waypointIndex);
}
/**
* Invoked when a player fired a skill event on self.
*
* Equivalent to 'function onSkillEventFired(self, msg)'
*/
void OnSkillEventFired(Entity* self, Entity* caster, const std::string& message) override {
Invoke("onSkillEventFired", lEntity(caster), message);
}
/**
* Invoked when self casted a skill.
*
* Equivalent to 'function onSkillCast(self, msg)'
*/
void OnSkillCast(Entity* self, uint32_t skillID) override {
Invoke("onSkillCast", skillID);
}
/**
* Invoked when a player on a rail reaches a waypoint
* Equivalent to: 'onPlayerRailArrivedNotification(self, msg)'
* @param self the parent of the script
* @param sender the entity that sent the event
* @param pathName the name of the path the entity was on
* @param waypoint the waypoint number of the path the entity was on
*/
void OnPlayerRailArrived(Entity* self, Entity* sender, const std::u16string& pathName, int32_t waypoint) override {
Invoke("onPlayerRailArrived", lEntity(sender), GeneralUtils::UTF16ToWTF8(pathName), waypoint);
}
/**
* Used by legacy minigames to indicate something has changed about the activity
* @param self the entity the script belongs to
* @param senderID the sender of the message
* @param value1 some value to represent the change
* @param value2 some other value to represent the change
* @param stringValue some string value to represent the change
*/
void OnActivityStateChangeRequest(Entity* self, const LWOOBJID senderID, const int32_t value1,
const int32_t value2, const std::u16string& stringValue) override {
Invoke("onActivityStateChangeRequest", senderID, value1, value2, GeneralUtils::UTF16ToWTF8(stringValue));
}
void OnCinematicUpdate(Entity* self, Entity* sender, eCinematicEvent event, const std::u16string& pathName,
float_t pathTime, float_t totalTime, int32_t waypoint) override {
Invoke("onCinematicUpdate", lEntity(sender), (int32_t) event, GeneralUtils::UTF16ToWTF8(pathName), pathTime, totalTime, waypoint);
}
};

View File

@ -0,0 +1,8 @@
#pragma once
enum class LuaTerminateBehavior
{
None,
ResetScript,
ResetScriptAndDelete,
};

155
dLua/dLua.cpp Normal file
View File

@ -0,0 +1,155 @@
#include "dLua.h"
#include "lEntity.h"
#include "EntityManager.h"
#include "LuaScript.h"
#include "LuaTerminateBehavior.h"
#include "ScriptComponent.h"
#include "Game.h"
#include "dLogger.h"
namespace dLua
{
void LoadScript(Entity* entity, const std::string& name)
{
// Read the script from the file.
std::stringstream input;
std::ifstream file(name);
if (!file.is_open())
throw std::runtime_error("LoadScript: Failed to open file");
std::string line;
while (std::getline(file, line)) {
input << line << "\n";
}
LuaScript* lua = new LuaScript(LuaTerminateBehavior::ResetScriptAndDelete);
ScriptComponent* script = entity->GetComponent<ScriptComponent>();
if (script == nullptr) {
script = new ScriptComponent(entity, false);
entity->AddComponent(ScriptComponent::ComponentType, script);
}
script->SetScript(lua);
lua->SetEntity(entity);
// Run the code, and print any errors
try {
lua->Script(input.str());
}
// Catch sol::error
catch (const sol::error& e) {
Game::logger->Log("dLua", std::string(e.what()));
}
// Catch *any* error
catch (...) {
Game::logger->Log("dLua", "Unknown error loading script!");
}
}
Entity* GetEntity(const sol::state& lua, const std::string& key)
{
sol::object object = lua[key];
if (!object.is<lEntity>())
return nullptr;
return object.as<lEntity>().GetEntity();
}
Entity* GetEntityOrThrow(const sol::state& lua, const std::string& key)
{
sol::object object = lua[key];
if (!object.is<lEntity>())
throw std::runtime_error("GetEntityOrThrow: Invalid key");
lEntity entity = object.as<lEntity>();
if (!entity.IsValid())
throw std::runtime_error("GetEntityOrThrow: Invalid entity");
return entity.GetEntity();
}
Entity* GetEntity(const LWOOBJID& id)
{
return EntityManager::Instance()->GetEntity(id);
}
Entity* GetEntityOrThrow(const LWOOBJID& id)
{
Entity* entity = EntityManager::Instance()->GetEntity(id);
if (!entity)
{
throw sol::error("Entity not found.");
}
return entity;
}
Entity* GetEntity(sol::object object)
{
LWOOBJID id = LWOOBJID_EMPTY;
if (object.is<lEntity>()) {
id = object.as<lEntity>().GetID();
} else if (object.is<LWOOBJID>()) {
id = object.as<LWOOBJID>();
} else if (object.is<std::string>()) {
id = atol(object.as<std::string>().c_str());
} else {
return nullptr;
}
return GetEntity(id);
}
Entity* GetEntityOrThrow(sol::object object)
{
Entity* entity = GetEntity(object);
if (!entity)
{
throw sol::error("Entity not found.");
}
return entity;
}
LWOOBJID GetEntityID(sol::object object)
{
LWOOBJID id = LWOOBJID_EMPTY;
if (object.is<lEntity>()) {
id = object.as<lEntity>().GetID();
} else if (object.is<LWOOBJID>()) {
id = object.as<LWOOBJID>();
} else if (object.is<std::string>()) {
id = atol(object.as<std::string>().c_str());
} else {
return LWOOBJID_EMPTY;
}
return id;
}
LWOOBJID GetEntityIDOrThrow(sol::object object)
{
LWOOBJID id = GetEntityID(object);
if (id == LWOOBJID_EMPTY)
{
throw sol::error("Entity not found.");
}
return id;
}
}

61
dLua/dLua.h Normal file
View File

@ -0,0 +1,61 @@
#pragma once
#include "sol/sol.hpp"
#include "dCommonVars.h"
class Entity;
namespace dLua
{
void LoadScript(Entity* entity, const std::string& name);
Entity* GetEntity(const sol::state& lua, const std::string& key);
Entity* GetEntityOrThrow(const sol::state& lua, const std::string& key);
Entity* GetEntity(const LWOOBJID& id);
Entity* GetEntityOrThrow(const LWOOBJID& id);
Entity* GetEntity(sol::object object);
Entity* GetEntityOrThrow(sol::object object);
LWOOBJID GetEntityID(sol::object object);
LWOOBJID GetEntityIDOrThrow(sol::object object);
template<typename T>
T TableGet(const sol::table& table, const std::string& key)
{
sol::object object = table[key];
if (!object.valid())
throw std::runtime_error("TableGet: Missing key");
if (!object.is<T>())
throw std::runtime_error("TableGet: Invalid key");
return object.as<T>();
}
template<typename T>
T TableGet(const sol::table& table, const std::string& key, const T& defaultValue)
{
sol::object object = table[key];
if (!object.valid())
return defaultValue;
if (!object.is<T>())
throw std::runtime_error("TableGet: Invalid key");
return object.as<T>();
}
template<typename T>
bool TryTableGet(const sol::table& table, const std::string& key, T& out)
{
sol::object object = table[key];
if (!object.valid())
return false;
if (!object.is<T>())
throw std::runtime_error("TableGet: Invalid key");
out = object.as<T>();
return true;
}
}

80
dLua/lCommonTypes.cpp Normal file
View File

@ -0,0 +1,80 @@
#include "lCommonTypes.h"
#include "NiPoint3.h"
#include "NiQuaternion.h"
#include "LuaScript.h"
void lCommonTypes::RegisterClass(LuaScript* script)
{
sol::state& lua = script->GetState();
lua.new_usertype<NiPoint3>(
"Vector3",
sol::constructors<NiPoint3(), NiPoint3(float, float, float)>(),
"x", &NiPoint3::x,
"y", &NiPoint3::y,
"z", &NiPoint3::z,
"dot", &NiPoint3::DotProduct,
"cross", &NiPoint3::CrossProduct,
"length", &NiPoint3::Length,
"squaredLength", &NiPoint3::SquaredLength,
"unitize", &NiPoint3::Unitize,
"normalize", &NiPoint3::Unitize,
"distance", &NiPoint3::Distance,
"distanceSquared", &NiPoint3::DistanceSquared,
"getX", &NiPoint3::GetX,
"getY", &NiPoint3::GetY,
"getZ", &NiPoint3::GetZ,
"setX", &NiPoint3::SetX,
"setY", &NiPoint3::SetY,
"setZ", &NiPoint3::SetZ,
sol::meta_function::to_string, [](const NiPoint3& vector) {
return "Vector3(" + std::to_string(vector.x) + ", " + std::to_string(vector.y) + ", " + std::to_string(vector.z) + ")";
},
sol::meta_function::addition, [](const NiPoint3& lhs, const NiPoint3& rhs) {
return lhs + rhs;
},
sol::meta_function::subtraction, [](const NiPoint3& lhs, const NiPoint3& rhs) {
return lhs - rhs;
},
sol::meta_function::multiplication, [](const NiPoint3& lhs, const float& rhs) {
return lhs * rhs;
},
sol::meta_function::division, [](const NiPoint3& lhs, const float& rhs) {
return lhs / rhs;
},
sol::meta_function::unary_minus, [](const NiPoint3& lhs) {
return lhs * -1.0f;
},
sol::meta_function::equal_to, [](const NiPoint3& lhs, const NiPoint3& rhs) {
return lhs == rhs;
}
);
lua.new_usertype<NiQuaternion>(
"Quaternion",
sol::constructors<NiQuaternion(), NiQuaternion(float, float, float, float)>(),
"x", &NiQuaternion::x,
"y", &NiQuaternion::y,
"z", &NiQuaternion::z,
"w", &NiQuaternion::w,
"getForwardVector", &NiQuaternion::GetForwardVector,
"getUpVector", &NiQuaternion::GetUpVector,
"getRightVector", &NiQuaternion::GetRightVector,
"getEulerAngles", &NiQuaternion::GetEulerAngles,
"getX", &NiQuaternion::GetX,
"getY", &NiQuaternion::GetY,
"getZ", &NiQuaternion::GetZ,
"getW", &NiQuaternion::GetW,
"setX", &NiQuaternion::SetX,
"setY", &NiQuaternion::SetY,
"setZ", &NiQuaternion::SetZ,
"setW", &NiQuaternion::SetW,
sol::meta_function::to_string, [](const NiQuaternion& quaternion) {
return "Quaternion(" + std::to_string(quaternion.x) + ", " + std::to_string(quaternion.y) + ", " + std::to_string(quaternion.z) + ", " + std::to_string(quaternion.w) + ")";
},
sol::meta_function::equal_to, [](const NiQuaternion& lhs, const NiQuaternion& rhs) {
return lhs == rhs;
}
);
}

12
dLua/lCommonTypes.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include "dLua.h"
class LuaScript;
/**
* A struct for wrapping a Position in Lua.
*/
struct lCommonTypes {
static void RegisterClass(LuaScript* script);
};

406
dLua/lEntity.cpp Normal file
View File

@ -0,0 +1,406 @@
#include "lEntity.h"
#include "EntityManager.h"
#include "Game.h"
#include "dLogger.h"
#include "LuaScript.h"
#include "DestroyableComponent.h"
#include "BaseCombatAIComponent.h"
#include "MovementAIComponent.h"
#include "GameMessages.h"
void lEntity::RegisterClass(LuaScript* script)
{
sol::state& lua = script->GetState();
lua.new_usertype<lEntity>("Entity",
sol::constructors<lEntity(LWOOBJID)>(),
"IsValid", &lEntity::IsValid,
"GetID", &lEntity::GetID,
"GetLOT", &lEntity::GetLOT,
"GetPosition", &lEntity::GetPosition,
"GetRotation", &lEntity::GetRotation,
"SetPosition", &lEntity::SetPosition,
"SetRotation", &lEntity::SetRotation,
"AddTimer", &lEntity::AddTimer,
"Smash", &lEntity::Smash,
"LoadScript", &lEntity::LoadScript,
"SetVar", &lEntity::SetVar,
"GetVar", [script](lEntity& entity, const std::string& key) {
return entity.GetVar(script, key);
},
#pragma region DestroyableComponent
"GetHealth", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->GetHealth();
},
"GetArmor", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->GetArmor();
},
"GetImagination", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->GetImagination();
},
"GetMaxHealth", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->GetMaxHealth();
},
"GetMaxArmor", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->GetMaxArmor();
},
"GetMaxImagination", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->GetMaxImagination();
},
"SetHealth", [](lEntity& entity, int32_t health) {
GetComponent<DestroyableComponent>(entity)->SetHealth(health);
},
"SetArmor", [](lEntity& entity, int32_t armor) {
GetComponent<DestroyableComponent>(entity)->SetArmor(armor);
},
"SetImagination", [](lEntity& entity, int32_t imagination) {
GetComponent<DestroyableComponent>(entity)->SetImagination(imagination);
},
"SetMaxHealth", [](lEntity& entity, float maxHealth) {
GetComponent<DestroyableComponent>(entity)->SetMaxHealth(maxHealth);
},
"SetMaxArmor", [](lEntity& entity, float maxArmor) {
GetComponent<DestroyableComponent>(entity)->SetMaxArmor(maxArmor);
},
"SetMaxImagination", [](lEntity& entity, float maxImagination) {
GetComponent<DestroyableComponent>(entity)->SetMaxImagination(maxImagination);
},
"Damage", [](lEntity& entity, int32_t damage, sol::object origin) {
GetComponent<DestroyableComponent>(entity)->Damage(damage, dLua::GetEntityID(origin));
},
"Heal", [](lEntity& entity, int32_t heal) {
GetComponent<DestroyableComponent>(entity)->Heal(heal);
},
"Repair", [](lEntity& entity, int32_t repair) {
GetComponent<DestroyableComponent>(entity)->Repair(repair);
},
"Imagine", [](lEntity& entity, int32_t imagine) {
GetComponent<DestroyableComponent>(entity)->Imagine(imagine);
},
"GetDamageToAbsorb", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->GetDamageToAbsorb();
},
"SetDamageToAbsorb", [](lEntity& entity, int32_t damageToAbsorb) {
GetComponent<DestroyableComponent>(entity)->SetDamageToAbsorb(damageToAbsorb);
},
"GetDamageReduction", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->GetDamageReduction();
},
"SetDamageReduction", [](lEntity& entity, int32_t damageReduction) {
GetComponent<DestroyableComponent>(entity)->SetDamageReduction(damageReduction);
},
"GetIsImmune", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->IsImmune();
},
"SetIsImmune", [](lEntity& entity, bool immune) {
GetComponent<DestroyableComponent>(entity)->SetIsImmune(immune);
},
"GetIsShielded", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->GetIsShielded();
},
"SetIsShielded", [](lEntity& entity, bool shielded) {
GetComponent<DestroyableComponent>(entity)->SetIsShielded(shielded);
},
"AddFaction", [](lEntity& entity, int32_t faction) {
GetComponent<DestroyableComponent>(entity)->AddFaction(faction);
},
"AddEnemyFaction", [](lEntity& entity, int32_t faction) {
GetComponent<DestroyableComponent>(entity)->AddEnemyFaction(faction);
},
"GetAttacksToBlock", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->GetAttacksToBlock();
},
"SetAttacksToBlock", [](lEntity& entity, int32_t attacksToBlock) {
GetComponent<DestroyableComponent>(entity)->SetAttacksToBlock(attacksToBlock);
},
"SetFaction", [](lEntity& entity, int32_t faction) {
GetComponent<DestroyableComponent>(entity)->SetFaction(faction);
},
"HasFaction", [](lEntity& entity, int32_t faction) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->HasFaction(faction);
},
"GetLootMatrixID", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->GetLootMatrixID();
},
"SetLootMatrixID", [](lEntity& entity, int32_t lootMatrixID) {
GetComponent<DestroyableComponent>(entity)->SetLootMatrixID(lootMatrixID);
},
"PushImmunity", [](lEntity& entity, int32_t immunity) {
GetComponent<DestroyableComponent>(entity)->PushImmunity(immunity);
},
"PopImmunity", [](lEntity& entity) {
GetComponent<DestroyableComponent>(entity)->PopImmunity();
},
"GetIsSmashable", [](lEntity& entity) {
AssertComponent<DestroyableComponent>(entity);
return entity->GetComponent<DestroyableComponent>()->GetIsSmashable();
},
"SetIsSmashable", [](lEntity& entity, bool smashable) {
GetComponent<DestroyableComponent>(entity)->SetIsSmashable(smashable);
},
#pragma endregion DestroyableComponent
#pragma region BaseCombatAIComponent
"GetStunned", [](lEntity& entity) {
AssertComponent<BaseCombatAIComponent>(entity);
return entity->GetComponent<BaseCombatAIComponent>()->GetStunned();
},
"SetStunned", [](lEntity& entity, bool stunned) {
AssertComponent<BaseCombatAIComponent>(entity);
entity->GetComponent<BaseCombatAIComponent>()->SetStunned(stunned);
},
"Stun", [](lEntity& entity, float duration) {
AssertComponent<BaseCombatAIComponent>(entity);
entity->GetComponent<BaseCombatAIComponent>()->Stun(duration);
},
"GetAIDisabled", [](lEntity& entity) {
AssertComponent<BaseCombatAIComponent>(entity);
return entity->GetComponent<BaseCombatAIComponent>()->GetDistabled();
},
"SetAIDisabled", [](lEntity& entity, bool disabled) {
AssertComponent<BaseCombatAIComponent>(entity);
entity->GetComponent<BaseCombatAIComponent>()->SetDisabled(disabled);
},
#pragma endregion BaseCombatAIComponent
#pragma region MovementAIComponent
"GetDestination", [](lEntity& entity) {
GetComponent<MovementAIComponent>(entity)->GetDestination();
},
"SetDestination", [](lEntity& entity, const NiPoint3& destination) {
GetComponent<MovementAIComponent>(entity)->SetDestination(destination);
},
"Warp", [](lEntity& entity, const NiPoint3& point) {
GetComponent<MovementAIComponent>(entity)->Warp(point);
},
#pragma endregion MovementAIComponent
#pragma region GameMessages
"PlayAnimation", [](lEntity& entity, const std::string& animation) {
GameMessages::SendPlayAnimation(entity.GetEntityOrThrow(), GeneralUtils::ASCIIToUTF16(animation));
},
"PlayFX", [](lEntity& entity, int32_t effectID, const std::string& effectType, const std::string& name) {
GameMessages::SendPlayFXEffect(entity.GetID(), effectID, GeneralUtils::ASCIIToUTF16(effectType), name);
},
"StopFX", [](lEntity& entity, const std::string& name, bool killImmediate) {
GameMessages::SendStopFXEffect(entity.GetEntityOrThrow(), killImmediate, name);
}
#pragma endregion GameMessages
);
// Register a function create a new entity
// Takes a table with the following fields:
// - lot: number
// - position: Vector3 (optional)
// - rotation: Quaternion (optional)
// - spawner: lEntity (optional)
lua.set_function("spawn", [script](sol::table entityData) {
sol::state& lua = script->GetState();
// Get the lot
LOT lot = dLua::TableGet<LOT>(entityData, "lot");
// Use the state entity's position and rotation if none is provided
Entity* stateEntity = script->GetEntity();
// Get the position
NiPoint3 position;
if (!dLua::TryTableGet(entityData, "position", position))
position = stateEntity->GetPosition();
// Get the rotation
NiQuaternion rotation;
if (!dLua::TryTableGet(entityData, "rotation", rotation))
rotation = stateEntity->GetRotation();
// Get the spawner
Entity* spawner = nullptr;
lEntity spawnerEntity;
if (dLua::TryTableGet(entityData, "spawner", spawnerEntity)) {
spawner = dLua::GetEntityOrThrow(spawnerEntity.id);
} else {
spawner = stateEntity;
}
// Create the entity
EntityInfo info {};
info.lot = lot;
info.pos = position;
info.rot = rotation;
info.spawnerID = spawner->GetObjectID();
Entity* entity = EntityManager::Instance()->CreateEntity(info);
EntityManager::Instance()->ConstructEntity(entity);
// Return the entity
return lEntity(entity->GetObjectID());
});
}
lEntity::lEntity(Entity* entity) {
if (entity == nullptr) {
this->id = LWOOBJID_EMPTY;
} else {
this->id = entity->GetObjectID();
}
}
bool lEntity::IsValid() const {
return GetEntity() != nullptr;
}
LWOOBJID lEntity::GetID() const {
return id;
}
LOT lEntity::GetLOT() const {
return GetEntityOrThrow()->GetLOT();
}
NiPoint3 lEntity::GetPosition() const {
return GetEntityOrThrow()->GetPosition();
}
NiQuaternion lEntity::GetRotation() const {
return GetEntityOrThrow()->GetRotation();
}
void lEntity::SetPosition(const NiPoint3& pos) {
GetEntityOrThrow()->SetPosition(pos);
}
void lEntity::SetRotation(const NiQuaternion& rot) {
GetEntityOrThrow()->SetRotation(rot);
}
void lEntity::SetVar(const std::string& key, sol::object value) {
const std::u16string key16 = GeneralUtils::ASCIIToUTF16(key);
Entity* entity = GetEntityOrThrow();
sol::type type = value.get_type();
if (value.is<lEntity>()) {
LWOOBJID entityID = value.as<lEntity>().GetID();
entity->SetVar(key16, entityID);
return;
}
switch (type) {
case sol::type::boolean:
entity->SetVar(key16, value.as<bool>());
break;
case sol::type::number:
entity->SetVar(key16, value.as<float>());
break;
case sol::type::string:
entity->SetVar(key16, GeneralUtils::ASCIIToUTF16(value.as<std::string>()));
break;
case sol::type::nil:
entity->SetVar(key16, value); // Maybe store nil some other way?
break;
default:
Game::logger->Log("lEntity", "Unknown type for SetVar: %i\n", type);
entity->SetVar(key16, value);
break;
}
}
sol::object lEntity::GetVar(LuaScript* script, const std::string& key) {
const std::u16string key16 = GeneralUtils::ASCIIToUTF16(key);
Entity* entity = GetEntityOrThrow();
LDFBaseData* value = entity->GetVarData(key16);
if (value == nullptr) {
return sol::make_object(script->GetState(), sol::nil);
}
eLDFType type = value->GetValueType();
sol::state& lua = script->GetState();
switch (type) {
case LDF_TYPE_UTF_16:
return sol::make_object(lua, GeneralUtils::UTF16ToWTF8(entity->GetVar<std::u16string>(key16)));
case LDF_TYPE_S32:
return sol::make_object(lua, entity->GetVar<int32_t>(key16));
case LDF_TYPE_FLOAT:
return sol::make_object(lua, entity->GetVar<float>(key16));
case LDF_TYPE_DOUBLE:
return sol::make_object(lua, entity->GetVar<double>(key16));
case LDF_TYPE_U32:
return sol::make_object(lua, entity->GetVar<uint32_t>(key16));
case LDF_TYPE_BOOLEAN:
return sol::make_object(lua, entity->GetVar<bool>(key16));
case LDF_TYPE_U64:
return sol::make_object(lua, entity->GetVar<uint64_t>(key16));
case LDF_TYPE_OBJID:
return sol::make_object(lua, lEntity(entity->GetVar<LWOOBJID>(key16)));
case LDF_TYPE_UTF_8:
return sol::make_object(lua, entity->GetVar<std::string>(key16));
default:
Game::logger->Log("lEntity", "Unknown type for GetVar: %i\n", type);
return entity->GetVar<sol::object>(key16);
}
}
void lEntity::Smash(sol::object smasher) {
Entity* entity = GetEntityOrThrow();
LWOOBJID smasherEntity = dLua::GetEntityID(smasher);
entity->Smash(smasherEntity);
}
void lEntity::AddTimer(const std::string& name, float seconds) {
GetEntityOrThrow()->AddTimer(name, seconds);
}
void lEntity::LoadScript(const std::string& name) {
dLua::LoadScript(GetEntityOrThrow(), name);
}
void lEntity::Serialize() {
EntityManager::Instance()->SerializeEntity(GetEntityOrThrow());
}
Entity* lEntity::GetEntity() const
{
return dLua::GetEntity(id);
}
Entity* lEntity::GetEntityOrThrow() const
{
return dLua::GetEntityOrThrow(id);
}
Entity* lEntity::operator->() const
{
return GetEntity();
}

122
dLua/lEntity.h Normal file
View File

@ -0,0 +1,122 @@
#pragma once
#include "dLua.h"
#include "Entity.h"
class LuaScript;
/**
* A struct for wrapping an Entity in Lua.
*/
struct lEntity {
static void RegisterClass(LuaScript* script);
LWOOBJID id;
lEntity() : id(LWOOBJID_EMPTY) {}
lEntity(LWOOBJID id) : id(id) {}
lEntity(Entity* entity);
/**
* Checks if this entity is valid.
*/
bool IsValid() const;
/**
* Get the entity's ID.
*/
LWOOBJID GetID() const;
/**
* Get the entity's lot.
*/
LOT GetLOT() const;
/**
* Get the entity's position.
*/
NiPoint3 GetPosition() const;
/**
* Get the entity's rotation.
*/
NiQuaternion GetRotation() const;
/**
* Set the entit's position.
*/
void SetPosition(const NiPoint3& pos);
/**
* Set the entity's rotation.
*/
void SetRotation(const NiQuaternion& rot);
/**
* Set a variable in the entity's data table.
*/
void SetVar(const std::string& key, sol::object value);
/**
* Get a variable from the entity's data table.
*/
sol::object GetVar(LuaScript* script, const std::string& key);
/**
* Smash this entity.
*/
void Smash(sol::object smasher);
/**
* Add a timer.
*/
void AddTimer(const std::string& name, float seconds);
/**
* Load a LUA script and attach it to this entity.
*/
void LoadScript(const std::string& name);
/**
* Serialize this entity.
*/
void Serialize();
Entity* GetEntity() const;
Entity* GetEntityOrThrow() const;
Entity* operator->() const;
/**
* Assets that this entity has a specific component.
*/
template <typename T>
void AssertComponent() {
if (!GetEntity()->HasComponent(T::ComponentType)) {
throw std::runtime_error("Entity does not have component " + std::to_string(T::ComponentType));
}
}
/**
* Assets that an entity has a specific component.
*/
template <typename T>
static inline void AssertComponent(lEntity entity) {
if (!entity->HasComponent(T::ComponentType)) {
throw std::runtime_error("Entity does not have component " + std::to_string(T::ComponentType));
}
}
/**
* Utility for getting a component, asserting it exists
*/
template <typename T>
static inline T* GetComponent(lEntity entity) {
entity.AssertComponent<T>();
return entity->GetComponent<T>();
}
};

53
dLua/sol/config.hpp Normal file
View File

@ -0,0 +1,53 @@
// The MIT License (MIT)
// Copyright (c) 2013-2020 Rapptz, ThePhD and contributors
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
// This file was generated with a script.
// Generated 2022-04-03 15:48:33.302370 UTC
// This header was generated with sol v4.0.0-alpha (revision 50b62c93)
// https://github.com/ThePhD/sol2
#ifndef SOL_SINGLE_CONFIG_HPP
#define SOL_SINGLE_CONFIG_HPP
// beginning of sol/config.hpp
/* Base, empty configuration file!
To override, place a file in your include paths of the form:
. (your include path here)
| sol (directory, or equivalent)
| config.hpp (your config.hpp file)
So that when sol2 includes the file
#include <sol/config.hpp>
it gives you the configuration values you desire. Configuration values can be
seen in the safety.rst of the doc/src, or at
https://sol2.readthedocs.io/en/latest/safety.html ! You can also pass them through
the build system, or the command line options of your compiler.
*/
// end of sol/config.hpp
#endif // SOL_SINGLE_CONFIG_HPP

1310
dLua/sol/forward.hpp Normal file

File diff suppressed because it is too large Load Diff

28843
dLua/sol/sol.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -812,6 +812,10 @@ CppScripts::Script* CppScripts::GetScript(Entity* parent, const std::string& scr
return script;
}
CppScripts::Script* CppScripts::GetInvalidScript() {
return invalidToReturn;
}
std::vector<CppScripts::Script*> CppScripts::GetEntityScripts(Entity* entity) {
std::vector<CppScripts::Script*> scripts;
std::vector<ScriptComponent*> comps = entity->GetScriptComponents();

View File

@ -320,6 +320,7 @@ namespace CppScripts {
float_t pathTime, float_t totalTime, int32_t waypoint) {};
};
Script* GetInvalidScript();
Script* GetScript(Entity* parent, const std::string& scriptName);
std::vector<Script*> GetEntityScripts(Entity* entity);
};

View File

@ -14,11 +14,22 @@ ScriptComponent::ScriptComponent(Entity* parent, std::string scriptName, bool se
SetScript(scriptName);
}
ScriptComponent::ScriptComponent(Entity* parent, bool serialized, bool client) : Component(parent) {
m_Serialized = serialized;
m_Client = client;
m_Script = nullptr;
}
ScriptComponent::~ScriptComponent() {
}
void ScriptComponent::Serialize(RakNet::BitStream* outBitStream, bool bIsInitialUpdate, unsigned int& flags) {
if (!m_Serialized) {
return;
}
if (bIsInitialUpdate) {
const auto& networkSettings = m_Parent->GetNetworkSettings();
auto hasNetworkSettings = !networkSettings.empty();
@ -55,3 +66,7 @@ void ScriptComponent::SetScript(const std::string& scriptName) {
m_Script = CppScripts::GetScript(m_Parent, scriptName);
}
void ScriptComponent::SetScript(CppScripts::Script* script) {
m_Script = script;
}

View File

@ -21,6 +21,7 @@ class ScriptComponent : public Component {
public:
static const uint32_t ComponentType = COMPONENT_TYPE_SCRIPT;
ScriptComponent(Entity* parent, bool serialized, bool client = false);
ScriptComponent(Entity* parent, std::string scriptName, bool serialized, bool client = false);
~ScriptComponent() override;
@ -44,6 +45,12 @@ public:
*/
void SetScript(const std::string& scriptName);
/**
* Sets the script directly
* @param script the script to set
*/
void SetScript(CppScripts::Script* script);
private:
/**