[Commands] Cleanup #object Command (#3722)

* [Commands] Cleanup #object Command

# Notes
- Cleanup messages and logic.
- Introduce enum for object types.
- Set ground work for object manipulation similar to door manipulation.

* Update object_manipulation.cpp

* Final push

* Update client_packet.cpp

* Update object_manipulation.cpp

* Update object_manipulation.cpp

* Update object.h

* Update client_packet.cpp

* Update client_packet.cpp

* Push.

* Update version.h

* Update database_update_manifest.cpp

* Update zone.cpp
This commit is contained in:
Alex King 2023-12-03 17:42:27 -05:00 committed by GitHub
parent 226cc3d6cb
commit b03f52de18
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1561 additions and 1394 deletions

View File

@ -5093,6 +5093,19 @@ RENAME TABLE `starting_items_new` TO `starting_items`;
.sql = R"(
ALTER TABLE `items` MODIFY COLUMN `updated` datetime NULL DEFAULT NULL;
)"
},
ManifestEntry{
.version = 9245,
.description = "2023_12_03_object_incline.sql",
.check = "SHOW COLUMNS FROM `object` LIKE 'incline'",
.condition = "empty",
.match = "",
.sql = R"(
ALTER TABLE `object`
CHANGE COLUMN `unknown08` `size_percentage` float NOT NULL DEFAULT 0 AFTER `icon`;
CHANGE COLUMN `unknown10` `solid_type` mediumint(5) NOT NULL DEFAULT 0 AFTER `size`,
CHANGE COLUMN `unknown20` `incline` int(11) NOT NULL DEFAULT 0 AFTER `solid_type`;
)"
}
// -- template; copy/paste this when you need to create a new entry

View File

@ -2594,11 +2594,11 @@ struct BookButton_Struct
struct Object_Struct {
/*00*/ uint32 linked_list_addr[2];// They are, get this, prev and next, ala linked list
/*08*/ float size; //
/*10*/ uint16 solidtype; //
/*10*/ uint16 solid_type; //
/*12*/ uint32 drop_id; // Unique object id for zone
/*16*/ uint16 zone_id; // Redudant, but: Zone the object appears in
/*18*/ uint16 zone_instance; //
/*20*/ uint32 unknown020; //
/*20*/ uint32 incline; //
/*24*/ uint32 unknown024; //
/*28*/ float tilt_x;
/*32*/ float tilt_y;

View File

@ -16,6 +16,7 @@
#include "../../strings.h"
#include <ctime>
class BaseObjectRepository {
public:
struct Object {
@ -31,9 +32,9 @@ public:
std::string objectname;
int32_t type;
int32_t icon;
int32_t unknown08;
int32_t unknown10;
int32_t unknown20;
float size_percentage;
int32_t solid_type;
int32_t incline;
int32_t unknown24;
int32_t unknown60;
int32_t unknown64;
@ -71,9 +72,9 @@ public:
"objectname",
"type",
"icon",
"unknown08",
"unknown10",
"unknown20",
"size_percentage",
"solid_type",
"incline",
"unknown24",
"unknown60",
"unknown64",
@ -107,9 +108,9 @@ public:
"objectname",
"type",
"icon",
"unknown08",
"unknown10",
"unknown20",
"size_percentage",
"solid_type",
"incline",
"unknown24",
"unknown60",
"unknown64",
@ -177,9 +178,9 @@ public:
e.objectname = "";
e.type = 0;
e.icon = 0;
e.unknown08 = 0;
e.unknown10 = 0;
e.unknown20 = 0;
e.size_percentage = 0;
e.solid_type = 0;
e.incline = 0;
e.unknown24 = 0;
e.unknown60 = 0;
e.unknown64 = 0;
@ -220,8 +221,9 @@ public:
{
auto results = db.QueryDatabase(
fmt::format(
"{} WHERE id = {} LIMIT 1",
"{} WHERE {} = {} LIMIT 1",
BaseSelect(),
PrimaryKey(),
object_id
)
);
@ -242,9 +244,9 @@ public:
e.objectname = row[9] ? row[9] : "";
e.type = static_cast<int32_t>(atoi(row[10]));
e.icon = static_cast<int32_t>(atoi(row[11]));
e.unknown08 = static_cast<int32_t>(atoi(row[12]));
e.unknown10 = static_cast<int32_t>(atoi(row[13]));
e.unknown20 = static_cast<int32_t>(atoi(row[14]));
e.size_percentage = strtof(row[12], nullptr);
e.solid_type = static_cast<int32_t>(atoi(row[13]));
e.incline = static_cast<int32_t>(atoi(row[14]));
e.unknown24 = static_cast<int32_t>(atoi(row[15]));
e.unknown60 = static_cast<int32_t>(atoi(row[16]));
e.unknown64 = static_cast<int32_t>(atoi(row[17]));
@ -304,9 +306,9 @@ public:
v.push_back(columns[9] + " = '" + Strings::Escape(e.objectname) + "'");
v.push_back(columns[10] + " = " + std::to_string(e.type));
v.push_back(columns[11] + " = " + std::to_string(e.icon));
v.push_back(columns[12] + " = " + std::to_string(e.unknown08));
v.push_back(columns[13] + " = " + std::to_string(e.unknown10));
v.push_back(columns[14] + " = " + std::to_string(e.unknown20));
v.push_back(columns[12] + " = " + std::to_string(e.size_percentage));
v.push_back(columns[13] + " = " + std::to_string(e.solid_type));
v.push_back(columns[14] + " = " + std::to_string(e.incline));
v.push_back(columns[15] + " = " + std::to_string(e.unknown24));
v.push_back(columns[16] + " = " + std::to_string(e.unknown60));
v.push_back(columns[17] + " = " + std::to_string(e.unknown64));
@ -355,9 +357,9 @@ public:
v.push_back("'" + Strings::Escape(e.objectname) + "'");
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.icon));
v.push_back(std::to_string(e.unknown08));
v.push_back(std::to_string(e.unknown10));
v.push_back(std::to_string(e.unknown20));
v.push_back(std::to_string(e.size_percentage));
v.push_back(std::to_string(e.solid_type));
v.push_back(std::to_string(e.incline));
v.push_back(std::to_string(e.unknown24));
v.push_back(std::to_string(e.unknown60));
v.push_back(std::to_string(e.unknown64));
@ -414,9 +416,9 @@ public:
v.push_back("'" + Strings::Escape(e.objectname) + "'");
v.push_back(std::to_string(e.type));
v.push_back(std::to_string(e.icon));
v.push_back(std::to_string(e.unknown08));
v.push_back(std::to_string(e.unknown10));
v.push_back(std::to_string(e.unknown20));
v.push_back(std::to_string(e.size_percentage));
v.push_back(std::to_string(e.solid_type));
v.push_back(std::to_string(e.incline));
v.push_back(std::to_string(e.unknown24));
v.push_back(std::to_string(e.unknown60));
v.push_back(std::to_string(e.unknown64));
@ -477,9 +479,9 @@ public:
e.objectname = row[9] ? row[9] : "";
e.type = static_cast<int32_t>(atoi(row[10]));
e.icon = static_cast<int32_t>(atoi(row[11]));
e.unknown08 = static_cast<int32_t>(atoi(row[12]));
e.unknown10 = static_cast<int32_t>(atoi(row[13]));
e.unknown20 = static_cast<int32_t>(atoi(row[14]));
e.size_percentage = strtof(row[12], nullptr);
e.solid_type = static_cast<int32_t>(atoi(row[13]));
e.incline = static_cast<int32_t>(atoi(row[14]));
e.unknown24 = static_cast<int32_t>(atoi(row[15]));
e.unknown60 = static_cast<int32_t>(atoi(row[16]));
e.unknown64 = static_cast<int32_t>(atoi(row[17]));
@ -531,9 +533,9 @@ public:
e.objectname = row[9] ? row[9] : "";
e.type = static_cast<int32_t>(atoi(row[10]));
e.icon = static_cast<int32_t>(atoi(row[11]));
e.unknown08 = static_cast<int32_t>(atoi(row[12]));
e.unknown10 = static_cast<int32_t>(atoi(row[13]));
e.unknown20 = static_cast<int32_t>(atoi(row[14]));
e.size_percentage = strtof(row[12], nullptr);
e.solid_type = static_cast<int32_t>(atoi(row[13]));
e.incline = static_cast<int32_t>(atoi(row[14]));
e.unknown24 = static_cast<int32_t>(atoi(row[15]));
e.unknown60 = static_cast<int32_t>(atoi(row[16]));
e.unknown64 = static_cast<int32_t>(atoi(row[17]));

View File

@ -42,7 +42,7 @@
* Manifest: https://github.com/EQEmu/Server/blob/master/utils/sql/db_update_manifest.txt
*/
#define CURRENT_BINARY_DATABASE_VERSION 9244
#define CURRENT_BINARY_DATABASE_VERSION 9245
#define CURRENT_BINARY_BOTS_DATABASE_VERSION 9040

View File

@ -10355,6 +10355,16 @@ void Client::SetDoorToolEntityId(uint16 door_tool_entity_id)
Client::m_door_tool_entity_id = door_tool_entity_id;
}
uint16 Client::GetObjectToolEntityId() const
{
return m_object_tool_entity_id;
}
void Client::SetObjectToolEntityId(uint16 object_tool_entity_id)
{
Client::m_object_tool_entity_id = object_tool_entity_id;
}
int Client::GetIPExemption()
{
return database.GetIPExemption(GetIPString());

View File

@ -1814,9 +1814,12 @@ private:
bool dev_tools_enabled;
uint16 m_door_tool_entity_id;
uint16 m_object_tool_entity_id;
public:
uint16 GetDoorToolEntityId() const;
void SetDoorToolEntityId(uint16 door_tool_entity_id);
uint16 GetObjectToolEntityId() const;
void SetObjectToolEntityId(uint16 object_tool_entity_id);
private:
int32 max_end;

View File

@ -60,6 +60,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "../common/repositories/criteria/content_filter_criteria.h"
#include "../common/shared_tasks.h"
#include "gm_commands/door_manipulation.h"
#include "gm_commands/object_manipulation.h"
#include "client.h"
#include "../common/repositories/account_repository.h"
@ -4650,6 +4651,20 @@ void Client::Handle_OP_ClickObject(const EQApplicationPacket *app)
std::vector<std::any> args = { object };
parse->EventPlayer(EVENT_CLICK_OBJECT, this, std::to_string(click_object->drop_id), GetID(), &args);
}
if (IsDevToolsEnabled()) {
SetObjectToolEntityId(entity->GetID());
ObjectManipulation::CommandHeader(this);
Message(
Chat::White,
fmt::format(
"Object ({}) [{}] [{}]",
entity->CastToObject()->GetDBID(),
Saylink::Silent("#object edit", "Edit"),
Saylink::Silent("#object delete", "Delete")
).c_str()
);
}
}
// Observed in RoF after OP_ClickObjectAction:

View File

@ -866,6 +866,7 @@ void command_bot(Client *c, const Seperator *sep)
#include "gm_commands/nukebuffs.cpp"
#include "gm_commands/nukeitem.cpp"
#include "gm_commands/object.cpp"
#include "gm_commands/object_manipulation.cpp"
#include "gm_commands/path.cpp"
#include "gm_commands/peqzone.cpp"
#include "gm_commands/petitems.cpp"

View File

@ -1,6 +1,5 @@
#include "../client.h"
#include "door_manipulation.h"
#include "../doors.h"
void command_door(Client *c, const Seperator *sep)
{

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
#ifndef EQEMU_OBJECT_MANIPULATION_H
#define EQEMU_OBJECT_MANIPULATION_H
#include "../client.h"
class ObjectManipulation {
public:
static void CommandHandler(Client *c, const Seperator *sep);
static void CommandHeader(Client *c);
static void SendSubcommands(Client *c);
};
#endif //EQEMU_OBJECT_MANIPULATION_H

View File

@ -40,19 +40,24 @@ extern EntityList entity_list;
extern WorldServer worldserver;
// Loading object from database
Object::Object(uint32 id, uint32 type, uint32 icon, const Object_Struct& object, const EQ::ItemInstance* inst)
: respawn_timer(0), decay_timer(300000)
Object::Object(
uint32 id,
uint32 type,
uint32 icon,
const Object_Struct &object,
const EQ::ItemInstance *inst
) : respawn_timer(0), decay_timer(300000)
{
user = nullptr;
user = nullptr;
last_user = nullptr;
// Initialize members
m_id = id;
m_type = type;
m_icon = icon;
m_inst = nullptr;
m_ground_spawn=false;
m_id = id;
m_type = type;
m_icon = icon;
m_inst = nullptr;
m_ground_spawn = false;
// Copy object data
memcpy(&m_data, &object, sizeof(Object_Struct));
if (inst) {
@ -61,13 +66,14 @@ Object::Object(uint32 id, uint32 type, uint32 icon, const Object_Struct& object,
} else {
decay_timer.Disable();
}
respawn_timer.Disable();
// Set drop_id to zero - it will be set when added to zone with SetID()
m_data.drop_id = 0;
m_data.size = object.size;
m_data.tilt_x = object.tilt_x;
m_data.tilt_y = object.tilt_y;
m_data.size = object.size;
m_data.tilt_x = object.tilt_x;
m_data.tilt_y = object.tilt_y;
FixZ();
}
@ -85,7 +91,7 @@ Object::Object(const EQ::ItemInstance* inst, char* name,float max_x,float min_x,
m_min_y=min_y;
m_id = 0;
m_inst = (inst) ? inst->Clone() : nullptr;
m_type = OT_DROPPEDITEM;
m_type = ObjectTypes::Temporary;
m_icon = 0;
m_ground_spawn = true;
decay_timer.Disable();
@ -116,7 +122,7 @@ Object::Object(Client* client, const EQ::ItemInstance* inst)
// Initialize members
m_id = 0;
m_inst = (inst) ? inst->Clone() : nullptr;
m_type = OT_DROPPEDITEM;
m_type = ObjectTypes::Temporary;
m_icon = 0;
m_ground_spawn = false;
// Set as much struct data as we can
@ -179,7 +185,7 @@ Object::Object(const EQ::ItemInstance *inst, float x, float y, float z, float he
// Initialize members
m_id = 0;
m_inst = (inst) ? inst->Clone() : nullptr;
m_type = OT_DROPPEDITEM;
m_type = ObjectTypes::Temporary;
m_icon = 0;
m_ground_spawn = false;
// Set as much struct data as we can
@ -436,7 +442,7 @@ void Object::CreateDeSpawnPacket(EQApplicationPacket* app)
}
bool Object::Process(){
if(m_type == OT_DROPPEDITEM && decay_timer.Enabled() && decay_timer.Check()) {
if(m_type == ObjectTypes::Temporary && decay_timer.Enabled() && decay_timer.Check()) {
// Send click to all clients (removes entity on client)
auto outapp = new EQApplicationPacket(OP_ClickObject, sizeof(ClickObject_Struct));
ClickObject_Struct* click_object = (ClickObject_Struct*)outapp->pBuffer;
@ -497,7 +503,7 @@ bool Object::HandleClick(Client* sender, const ClickObject_Struct* click_object)
if(m_ground_spawn) {//This is a Cool Groundspawn
respawn_timer.Start();
}
if (m_type == OT_DROPPEDITEM) {
if (m_type == ObjectTypes::Temporary) {
bool cursordelete = false;
bool duplicate_lore = false;
if (m_inst && sender) {
@ -969,7 +975,7 @@ void Object::SetSize(float size)
void Object::SetSolidType(uint16 solidtype)
{
m_data.solidtype = solidtype;
m_data.solid_type = solidtype;
auto app = new EQApplicationPacket();
auto app2 = new EQApplicationPacket();
CreateDeSpawnPacket(app);
@ -987,7 +993,7 @@ float Object::GetSize()
uint16 Object::GetSolidType()
{
return m_data.solidtype;
return m_data.solid_type;
}
const char* Object::GetModelName()

View File

@ -73,8 +73,6 @@ IT10714_ACTORDEF=Augmentation Sealer
IT10725_ACTORDEF=Shuriken
*/
#define OT_DROPPEDITEM EQ::item::BagTypeLargeBag
// Icon values:
//0x0453 a pie
//0x0454 cookies?
@ -89,6 +87,51 @@ IT10725_ACTORDEF=Shuriken
//0x045D is a hammer
//0x045E is a wierd rope shape
enum ObjectTypes {
StaticLocked = 0,
Temporary = 1,
ToolBox = 10,
Research = 11,
Mortar = 12,
SelfDusting = 13,
Baking1 = 14,
Baking2 = 15,
Tailoring = 16,
Forge = 17,
Fletching = 18,
BrewBarrel = 19,
Jewelcrafting = 20,
PotteryWheel = 21,
PotteryKiln = 22,
WizardResearch = 24,
MagicianResearch = 25,
NecromancerResearch = 26,
EnchanterResearch = 27,
Invalid1 = 28,
Invalid2 = 29,
Experimental = 30,
HighElfForge = 31,
DarkElfForge = 32,
OgreForge = 33,
DwarfForge = 34,
GnomeForge = 35,
BarbarianForge = 36,
IksarForge = 38,
HumanForge = 39,
HumanForge2 = 40,
HalflingTailoring = 41,
EruditeTailoring = 42,
WoodElfTailoring = 43,
WoodElfFletching = 44,
IksarPotteryWheel = 45,
TrollForge = 47,
WoodElfForge = 48,
HalflingForge = 49,
EruditeForge = 50,
AugmentationPool = 53,
StaticUnlocked = 255
};
class Object: public Entity
{
public:

View File

@ -56,6 +56,7 @@
#include "zone_reload.h"
#include "../common/repositories/criteria/content_filter_criteria.h"
#include "../common/repositories/merchantlist_repository.h"
#include "../common/repositories/object_repository.h"
#include "../common/repositories/rule_sets_repository.h"
#include "../common/serverinfo.h"
@ -172,101 +173,94 @@ bool Zone::Bootup(uint32 iZoneID, uint32 iInstanceID, bool is_static) {
//this really loads the objects into entity_list
bool Zone::LoadZoneObjects()
{
std::string query = StringFormat(
"SELECT id, zoneid, xpos, ypos, zpos, heading, itemid, charges, objectname, type, icon, "
"unknown08, unknown10, unknown20, unknown24, unknown76, size, tilt_x, tilt_y, display_name "
"FROM object WHERE zoneid = %i AND (version = %u OR version = -1) %s",
zoneid,
instanceversion,
ContentFilterCriteria::apply().c_str()
const auto &l = ObjectRepository::GetWhere(
content_db,
fmt::format(
"zoneid = {} AND (version = {} OR version = -1) {}",
zoneid,
instanceversion,
ContentFilterCriteria::apply()
)
);
auto results = content_db.QueryDatabase(query);
if (!results.Success()) {
LogError("Error Loading Objects from DB: [{}]",
results.ErrorMessage().c_str());
if (l.empty()) {
LogError("Error Loading Objects for Zone [{}] Version [{}]", zoneid, instanceversion);
return false;
}
for (auto row = results.begin(); row != results.end(); ++row) {
if (Strings::ToInt(row[9]) == 0) {
// Type == 0 - Static Object
const char *shortname = ZoneName(Strings::ToInt(row[1]), false); // zoneid -> zone_shortname
for (const auto &e : l) {
if (e.type == ObjectTypes::StaticLocked) {
const std::string &zone_short_name = ZoneName(e.zoneid, false);
if (!shortname)
if (zone_short_name.empty()) {
continue;
}
// todo: clean up duplicate code with command_object
auto d = DoorsRepository::NewEntity();
d.zone = shortname;
d.id = 1000000000 + Strings::ToInt(row[0]); // Out of range of normal use for doors.id
d.doorid = -1; // Client doesn't care if these are all the same door_id
d.pos_x = Strings::ToFloat(row[2]); // xpos
d.pos_y = Strings::ToFloat(row[3]); // ypos
d.pos_z = Strings::ToFloat(row[4]); // zpos
d.heading = Strings::ToFloat(row[5]); // heading
d.zone = zone_short_name;
d.id = 1000000000 + e.id;
d.doorid = -1;
d.pos_x = e.xpos;
d.pos_y = e.ypos;
d.pos_z = e.zpos;
d.heading = e.heading;
d.name = Strings::Replace(e.objectname, "_ACTORDEF", "");
d.dest_zone = "NONE";
d.incline = e.incline;
d.client_version_mask = 0xFFFFFFFF;
d.name = row[8]; // objectname
// Strip trailing "_ACTORDEF" if present. Client won't accept it for doors.
int pos = d.name.size() - strlen("_ACTORDEF");
if (pos > 0 && d.name.compare(pos, std::string::npos, "_ACTORDEF") == 0)
{
d.name.erase(pos);
}
d.dest_zone = "NONE";
if ((d.size = Strings::ToInt(row[11])) == 0) // unknown08 = optional size percentage
if (e.size_percentage == 0) {
d.size = 100;
switch (d.opentype = Strings::ToInt(row[12])) // unknown10 = optional request_nonsolid (0 or 1 or experimental number)
{
case 0:
d.opentype = 31;
break;
case 1:
d.opentype = 9;
break;
}
d.incline = Strings::ToInt(row[13]); // unknown20 = optional model incline value
d.client_version_mask = 0xFFFFFFFF; // We should load the mask from the zone.
switch (d.opentype = e.solid_type)
{
case 0:
d.opentype = 31;
break;
case 1:
d.opentype = 9;
break;
}
auto door = new Doors(d);
entity_list.AddDoor(door);
}
Object_Struct data = {0};
uint32 id = 0;
uint32 icon = 0;
uint32 type = 0;
uint32 itemid = 0;
uint32 idx = 0;
int16 charges = 0;
Object_Struct data = {0};
uint32 id = 0;
uint32 icon = 0;
uint32 type = 0;
uint32 itemid = 0;
uint32 idx = 0;
int16 charges = 0;
id = e.id;
data.zone_id = e.zoneid;
data.x = e.xpos;
data.y = e.ypos;
data.z = e.zpos;
data.heading = e.heading;
itemid = e.itemid;
charges = e.charges;
type = e.type;
icon = e.icon;
id = (uint32)Strings::ToInt(row[0]);
data.zone_id = Strings::ToInt(row[1]);
data.x = Strings::ToFloat(row[2]);
data.y = Strings::ToFloat(row[3]);
data.z = Strings::ToFloat(row[4]);
data.heading = Strings::ToFloat(row[5]);
itemid = (uint32)Strings::ToInt(row[6]);
charges = (int16)Strings::ToInt(row[7]);
strcpy(data.object_name, row[8]);
type = (uint8)Strings::ToInt(row[9]);
icon = (uint32)Strings::ToInt(row[10]);
data.object_type = type;
data.linked_list_addr[0] = 0;
data.linked_list_addr[1] = 0;
data.solidtype = (uint32)Strings::ToInt(row[12]);
data.unknown020 = (uint32)Strings::ToInt(row[13]);
data.unknown024 = (uint32)Strings::ToInt(row[14]);
data.unknown076 = (uint32)Strings::ToInt(row[15]);
data.size = Strings::ToFloat(row[16]);
data.tilt_x = Strings::ToFloat(row[17]);
data.tilt_y = Strings::ToFloat(row[18]);
strn0cpy(data.object_name, e.objectname.c_str(), sizeof(data.object_name));
data.solid_type = e.solid_type;
data.incline = e.incline;
data.unknown024 = e.unknown24;
data.unknown076 = e.unknown76;
data.size = e.size;
data.tilt_x = e.tilt_x;
data.tilt_y = e.tilt_y;
data.unknown084 = 0;
@ -280,9 +274,8 @@ bool Zone::LoadZoneObjects()
}
EQ::ItemInstance *inst = nullptr;
// FatherNitwit: this dosent seem to work...
// tradeskill containers do not have an itemid of 0... at least what I am seeing
if (itemid == 0) {
// tradeskill containers do not have an itemid of 0
if (!itemid) {
// Generic tradeskill container
inst = new EQ::ItemInstance(ItemInstWorldContainer);
} else {
@ -290,8 +283,7 @@ bool Zone::LoadZoneObjects()
inst = database.CreateItem(itemid);
}
// Father Nitwit's fix... not perfect...
if (inst == nullptr && type != OT_DROPPEDITEM) {
if (!inst && type != ObjectTypes::Temporary) {
inst = new EQ::ItemInstance(ItemInstWorldContainer);
}
@ -301,15 +293,17 @@ bool Zone::LoadZoneObjects()
}
auto object = new Object(id, type, icon, data, inst);
object->SetDisplayName(row[19]);
object->SetDisplayName(e.display_name.c_str());
entity_list.AddObject(object, false);
if (type == OT_DROPPEDITEM && itemid != 0)
if (type == ObjectTypes::Temporary && itemid) {
entity_list.RemoveObject(object->GetID());
}
safe_delete(inst);
}
LogInfo("Loaded [{}] world objects", Strings::Commify(results.RowCount()));
LogInfo("Loaded [{}] world objects", Strings::Commify(l.size()));
return true;
}