mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2024-11-26 15:37:20 +00:00
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:
parent
a0a9936e47
commit
5f689104af
@ -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.
|
||||
|
@ -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
135
dLua/LuaScript.cpp
Normal 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
426
dLua/LuaScript.h
Normal 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);
|
||||
}
|
||||
};
|
8
dLua/LuaTerminateBehavior.h
Normal file
8
dLua/LuaTerminateBehavior.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
enum class LuaTerminateBehavior
|
||||
{
|
||||
None,
|
||||
ResetScript,
|
||||
ResetScriptAndDelete,
|
||||
};
|
155
dLua/dLua.cpp
Normal file
155
dLua/dLua.cpp
Normal 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
61
dLua/dLua.h
Normal 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
80
dLua/lCommonTypes.cpp
Normal 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
12
dLua/lCommonTypes.h
Normal 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
406
dLua/lEntity.cpp
Normal 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
122
dLua/lEntity.h
Normal 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
53
dLua/sol/config.hpp
Normal 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
1310
dLua/sol/forward.hpp
Normal file
File diff suppressed because it is too large
Load Diff
28843
dLua/sol/sol.hpp
Normal file
28843
dLua/sol/sol.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -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();
|
||||
|
@ -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);
|
||||
};
|
@ -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;
|
||||
}
|
||||
|
@ -20,7 +20,8 @@ class Entity;
|
||||
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:
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user