修正[自定义AI_物体]

1、去除PlayerScript方式、使用AllGameObjectScript
2、使用unordered_map按entry分组存储,提高查找效率
This commit is contained in:
尚美 2025-08-14 14:50:58 +08:00
parent c084a36878
commit 74df244836
3 changed files with 187 additions and 166 deletions

View File

@ -54,8 +54,9 @@ void AddSC_Random_Enchant();
void AddSC_RECRUIT();
void AddSC_Reincarnation();
void AddSC_ResetInsNPC();
void AddSC_CustomCreatureScript(); // 自定义AI_生物
void AddSC_CustomRandSpellScript(); // 随机技能组
void AddSC_CustomCreatureScript(); // 自定义AI_生物
void AddSC_CustomRandSpellScript(); // 随机技能组
void AddSC_CustomGameObjectScript(); // 自定义AI_物体
void AddSC_SpellScripts();
void AddSC_SignIn();
void AddSC_CUSTOM_SKILL();
@ -170,8 +171,9 @@ void Addmod_GhostScriptsScripts(){
AddSC_RECRUIT();
AddSC_Reincarnation();
AddSC_ResetInsNPC();
AddSC_CustomCreatureScript(); // 自定义AI_生物
AddSC_CustomRandSpellScript(); // 随机技能组
AddSC_CustomCreatureScript(); // 自定义AI_生物
AddSC_CustomRandSpellScript(); // 随机技能组
AddSC_CustomGameObjectScript(); // 自定义AI_物体
AddSC_SpellScripts();
AddSC_SignIn();
AddSC_CUSTOM_SKILL();

View File

@ -148,7 +148,14 @@ public:
void CastSpellToNearbyUnits(Unit* caster, uint32 e_spellId, uint32 f_spellId, float range);
void ReloadCreatureAI(uint32 entry); // 强制重新分配AI
bool HasCustomScript(uint32 entry);
void ExecuteScript(Player* player, GameObject* gob);
private:
// 使用unordered_map按entry分组存储提高查找效率
std::unordered_map<uint32, std::vector<GobScriptTemplate>> GobScriptMap;
void Tele(Player* player, uint32 telePosId);
};
#define sCustomScript CustomScript::instance()

View File

@ -6,228 +6,240 @@
#include "mod_CustomEvent/Event.h"
#include "mod_CustomWorldData/mod_CustomWorldData.h"
#include <WorldSessionMgr.h>
std::vector<GobScriptTemplate> GobScriptVec;
#include <Scripting/ScriptMgrMacros.h>
void CustomScript::LoadGobScripts()
{
uint32 oldMSTime = getMSTime();
GobScriptVec.clear();
GobScriptMap.clear();
QueryResult result = WorldDatabase.Query("SELECT 物体ID,动作类型,动作参数1,动作参数2 FROM acore_custom._自定义AI_物体");
if (result)
{
do
{
Field* fields = result->Fetch();
GobScriptTemplate Temp;
Temp.ID = fields[0].Get<int32>();
GobScriptTemplate temp;
temp.ID = fields[0].Get<int32>();
std::string str2 = fields[1].Get<std::string>();
if (!str2.empty())
{
if (strcmp("传送玩家", str2.c_str()) == 0)
Temp.gobActionType = gob_ACTION_TYPE_TELE;
temp.gobActionType = gob_ACTION_TYPE_TELE;
else if (strcmp("激活或使失活", str2.c_str()) == 0)
Temp.gobActionType = gob_ACTION_TYPE_ACTIVE_OR_DEACTIVE_OBJECT;
temp.gobActionType = gob_ACTION_TYPE_ACTIVE_OR_DEACTIVE_OBJECT;
else if (strcmp("释放技能", str2.c_str()) == 0)
Temp.gobActionType = gob_ACTION_TYPE_AURA;
temp.gobActionType = gob_ACTION_TYPE_AURA;
else if (strcmp("说话", str2.c_str()) == 0)
Temp.gobActionType = gob_ACTION_TALK;
temp.gobActionType = gob_ACTION_TALK;
else if (strcmp("召唤", str2.c_str()) == 0)
Temp.gobActionType = gob_ACTION_SUMMON;
temp.gobActionType = gob_ACTION_SUMMON;
else
Temp.gobActionType = gob_ACTION_TYPE_NONE;
temp.gobActionType = gob_ACTION_TYPE_NONE;
}
Temp.actionParam1 = fields[2].Get<std::string>();
Temp.actionParam2 = fields[3].Get<int32>();
temp.actionParam1 = fields[2].Get<std::string>();
temp.actionParam2 = fields[3].Get<int32>();
// 按entry分组存储
uint32 entry = abs(temp.ID);
GobScriptMap[entry].push_back(temp);
GobScriptVec.push_back(Temp);
} while (result->NextRow());
sLog->outMessage("server", LogLevel::LOG_LEVEL_INFO, ">> 读取自定义功能数据表【_自定义AI_物体------------】,共{}条数据读取加载,用时{}毫秒", GobScriptVec.size(), GetMSTimeDiffToNow(oldMSTime));
}
sLog->outMessage("server", LogLevel::LOG_LEVEL_INFO,
">> 读取自定义功能数据表【_自定义AI_物体】,共{}个物体,{}条脚本数据,用时{}毫秒",
GobScriptMap.size(),
[this]() {
uint32 total = 0;
for (const auto& pair : GobScriptMap)
total += pair.second.size();
return total;
}(),
GetMSTimeDiffToNow(oldMSTime));
}
}
class CustomGameObject : PlayerScript
bool CustomScript::HasCustomScript(uint32 entry)
{
public:
CustomGameObject() : PlayerScript("CustomGameObject") {}
auto it = GobScriptMap.find(entry);
return it != GobScriptMap.end() && !it->second.empty();
}
void OnUseGameObject(Player* player, GameObject* gob)
void CustomScript::ExecuteScript(Player* player, GameObject* gob)
{
uint32 entry = gob->GetEntry();
int32 guid = gob->GetGUID().GetCounter();
// 快速查找对应的脚本
auto it = GobScriptMap.find(entry);
if (it == GobScriptMap.end())
return;
for (const auto& script : it->second)
{
uint32 entry = gob->GetEntry();
int32 guid = gob->GetGUID();
// 检查是否匹配entry或guid
if (script.ID != entry && guid != abs(script.ID))
continue;
for (std::vector<GobScriptTemplate>::iterator itr = GobScriptVec.begin(); itr != GobScriptVec.end(); ++itr)
int32 i_actionParam1 = atoi(script.actionParam1.c_str());
std::string s_actionParam1 = script.actionParam1;
int32 i_actionParam2 = script.actionParam2;
switch (script.gobActionType)
{
int32 ID = itr->ID;
case gob_ACTION_TYPE_AURA:
player->CastSpell(player, i_actionParam1, true);
if (i_actionParam2 > 0)
player->CastSpell(player, i_actionParam2, true);
break;
if (ID != entry && guid != abs(ID))
continue;
int32 i_actionParam1 = atoi(itr->actionParam1.c_str());
std::string s_actionParam1 = itr->actionParam1;
int32 i_actionParam2 = itr->actionParam2;
GobActionTypes gobActionType = itr->gobActionType;
switch (gobActionType)
case gob_ACTION_TYPE_TELE:
if (!player->HasAura(i_actionParam2))
{
case gob_ACTION_TYPE_AURA:
player->AddAura(i_actionParam1, player);
player->AddAura(i_actionParam2, player);
break;
case gob_ACTION_TYPE_TELE:
if (!player->HasAura(i_actionParam2))
{
player->AddAura(i_actionParam2, player);
Tele(player, i_actionParam1);
}
else
{
std::ostringstream oss;
oss << "|cFFFF1717[" << gob->GetName() << "]|r正处于冷却中传送失败...";
player->GetSession()->SendAreaTriggerMessage(oss.str().c_str());
}
break;
case gob_ACTION_TYPE_ACTIVE_OR_DEACTIVE_OBJECT:
Tele(player, i_actionParam1);
}
else
{
uint32 guid = abs(i_actionParam1);
bool isCreature = i_actionParam2 == 0 ? true : false;
bool active = i_actionParam1 > 0 ? true : false;
std::ostringstream oss;
oss << "|cFFFF1717[" << gob->GetName() << "]|r正处于冷却中传送失败...";
player->GetSession()->SendAreaTriggerMessage(oss.str().c_str());
}
break;
/*if (isCreature)
{
if (CreatureData const* data = sObjectMgr->GetCreatureData(guid))
if (Creature* target = ObjectAccessor::GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_UNIT), (Creature*)NULL))
active ? target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE) : target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
}
else
{
if (GameObjectData const* data = sObjectMgr->GetGOData(guid))
if (GameObject* target = ObjectAccessor::GetObjectInWorld(MAKE_NEW_GUID(guid, data->id, HIGHGUID_GAMEOBJECT), (GameObject*)NULL))
active ? target->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE) : target->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
}*/
case gob_ACTION_TYPE_ACTIVE_OR_DEACTIVE_OBJECT:
{
uint32 targetGuid = abs(i_actionParam1);
bool isCreature = i_actionParam2 == 0;
bool active = i_actionParam1 > 0;
if (isCreature)
if (isCreature)
{
if (CreatureData const* data = sObjectMgr->GetCreatureData(targetGuid))
{
if (CreatureData const* data = sObjectMgr->GetCreatureData(guid))
ObjectGuid creatureGuid = ObjectGuid(HighGuid::Unit, data->id1, targetGuid);
if (Creature* target = ObjectAccessor::GetCreature(*player, creatureGuid))
{
ObjectGuid creatureGuid = ObjectGuid(HighGuid::Unit, data->id1, static_cast<uint32>(guid));
// 使用GUID获取Creature
if (Creature* target = ObjectAccessor::GetCreature(*player, creatureGuid))
{
active ? target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE) : target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
}
}
}
else
{
if (GameObjectData const* data = sObjectMgr->GetGameObjectData(guid))
{
ObjectGuid gameObjectGuid = ObjectGuid(HighGuid::GameObject, data->id, static_cast<uint32>(guid));
// 使用GUID获取GameObject
if (GameObject* target = ObjectAccessor::GetGameObject(*player, gameObjectGuid))
{
active ? target->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE) : target->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
}
if (active)
target->RemoveFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
else
target->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_NON_ATTACKABLE | UNIT_FLAG_NOT_SELECTABLE);
}
}
}
break;
case gob_ACTION_TALK:
switch (i_actionParam2)
{
// 1zone text 2 中间刷屏 3 两者都有
case 1:
sWorldSessionMgr->SendZoneText(player->GetZoneId(), s_actionParam1.c_str());
break;
case 2:
{
WorldSessionMgr::SessionMap m_sessions = sWorldSessionMgr->GetAllSessions();
for (WorldSessionMgr::SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if (!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld() || itr->second->GetPlayer()->GetZoneId() != gob->GetZoneId())
continue;
itr->second->SendAreaTriggerMessage(s_actionParam1.c_str());
}
}
break;
case 3:
{
WorldSessionMgr::SessionMap m_sessions = sWorldSessionMgr->GetAllSessions();
for (WorldSessionMgr::SessionMap::const_iterator itr = m_sessions.begin(); itr != m_sessions.end(); ++itr)
{
if (!itr->second || !itr->second->GetPlayer() || !itr->second->GetPlayer()->IsInWorld() || itr->second->GetPlayer()->GetZoneId() != gob->GetZoneId())
continue;
itr->second->SendAreaTriggerMessage(s_actionParam1.c_str());
}
sWorldSessionMgr->SendZoneText(player->GetZoneId(), s_actionParam1.c_str());
}
break;
case 4:
sCustomWorldData->SendScreenMessage(s_actionParam1.c_str());
break;
default:
break;
}
break;
case gob_ACTION_SUMMON:
else
{
bool isCreature = i_actionParam1 > 0 ? true : false;
uint32 entry = abs(i_actionParam1);
uint32 despawntime = i_actionParam2 * MINUTE * IN_MILLISECONDS;
if (isCreature)
gob->SummonCreature(entry, gob->GetPositionX(), gob->GetPositionY(), gob->GetPositionZ(), gob->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, despawntime);
else
gob->SummonGameObject(entry, gob->GetPositionX(), gob->GetPositionY(), gob->GetPositionZ(), gob->GetOrientation(), 0, 0, 0, 0, despawntime);
}
break;
default:
break;
if (GameObjectData const* data = sObjectMgr->GetGameObjectData(targetGuid))
{
ObjectGuid gameObjectGuid = ObjectGuid(HighGuid::GameObject, data->id, targetGuid);
if (GameObject* target = ObjectAccessor::GetGameObject(*player, gameObjectGuid))
{
if (active)
target->RemoveFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
else
target->SetFlag(GAMEOBJECT_FLAGS, GO_FLAG_NOT_SELECTABLE);
}
}
}
}
break;
case gob_ACTION_TALK:
switch (i_actionParam2)
{
case 1:
sWorldSessionMgr->SendZoneText(player->GetZoneId(), s_actionParam1.c_str());
break;
case 2:
{
WorldSessionMgr::SessionMap m_sessions = sWorldSessionMgr->GetAllSessions();
for (auto const& session : m_sessions)
{
if (!session.second || !session.second->GetPlayer() ||
!session.second->GetPlayer()->IsInWorld() ||
session.second->GetPlayer()->GetZoneId() != gob->GetZoneId())
continue;
session.second->SendAreaTriggerMessage(s_actionParam1.c_str());
}
}
break;
case 3:
{
WorldSessionMgr::SessionMap m_sessions = sWorldSessionMgr->GetAllSessions();
for (auto const& session : m_sessions)
{
if (!session.second || !session.second->GetPlayer() ||
!session.second->GetPlayer()->IsInWorld() ||
session.second->GetPlayer()->GetZoneId() != gob->GetZoneId())
continue;
session.second->SendAreaTriggerMessage(s_actionParam1.c_str());
}
sWorldSessionMgr->SendZoneText(player->GetZoneId(), s_actionParam1.c_str());
}
break;
case 4:
sCustomWorldData->SendScreenMessage(s_actionParam1.c_str());
break;
}
break;
case gob_ACTION_SUMMON:
{
bool isCreature = i_actionParam1 > 0;
uint32 summonEntry = abs(i_actionParam1);
uint32 despawntime = i_actionParam2 * MINUTE * IN_MILLISECONDS;
if (isCreature)
gob->SummonCreature(summonEntry, gob->GetPositionX(), gob->GetPositionY(),
gob->GetPositionZ(), gob->GetOrientation(), TEMPSUMMON_TIMED_DESPAWN, despawntime);
else
gob->SummonGameObject(summonEntry, gob->GetPositionX(), gob->GetPositionY(),
gob->GetPositionZ(), gob->GetOrientation(), 0, 0, 0, 0, despawntime);
}
break;
}
}
}
void Tele(Player* player, uint32 telePosId)
void CustomScript::Tele(Player* player, uint32 telePosId)
{
// 这里需要访问PosMap可能需要从Event模块获取
// 或者重新设计传送位置的获取方式
if (sEvent)
{
std::unordered_map<uint32, PosTemplate>::iterator it = PosMap.find(telePosId);
if (it != PosMap.end())
player->TeleportTo(it->second.map, it->second.x, it->second.y, it->second.z, it->second.o);
uint32 map;
float x, y, z, o;
sEvent->GetTelePos(telePosId, map, x, y, z, o);
player->TeleportTo(map, x, y, z, o);
}
};
}
class KeyStone :public GameObjectScript
class CustomGameObjectHook : public AllGameObjectScript
{
public:
KeyStone() : GameObjectScript("KeyStone") { }
CustomGameObjectHook() : AllGameObjectScript("CustomGameObjectHook") {}
bool OnGossipHello(Player* player, GameObject* go) override
void OnGameObjectAddWorld(GameObject* go) override
{
if (Creature* target = go->FindNearestCreature(1, 5.0f))
{
go->CastSpell(target, 64986);
target->SetVisible(true);
}
return true;
if (!go)
return;
}
bool OnGossipSelect(Player* player, GameObject* go, uint32 sender, uint32 action) override
bool CanGameObjectGossipHello(Player* player, GameObject* go) override
{
return true;
// 检查是否有自定义脚本
if (sCustomScript->HasCustomScript(go->GetEntry()))
{
sCustomScript->ExecuteScript(player, go);
return true; // 阻止默认处理
}
return false;
}
};
void AddSC_CustomGameObjectScript()
{
new KeyStone();
new CustomGameObject();
new CustomGameObjectHook();
}