diff --git a/common/message.proto b/common/message.proto index 6b904ad18..9f9b1dd86 100644 --- a/common/message.proto +++ b/common/message.proto @@ -19,22 +19,26 @@ message ChannelMessage { bool is_emote = 12; //0 not queued, 1 queued, 2 queue full, 3 offline int32 queued = 13; - string result = 15; + string result = 15; //Result of channel request. 1 = Success, Non-numeric = error + int32 from_entity_id = 16; //(Only in zone requests) Entity to send message from + EntityType from_entity_type = 17; //(Only in zone requests) Entity type the message is from + float distance = 18; //(optional, only in zone requests) how far should the message travel? (e.g. say) + bool skip_sender = 19; //(optional, only in zone requests) should we skip sender? } message CommandMessage { - string author = 1; - string command = 2; - repeated string params = 3; - string result = 4; - bytes payload = 5; + string author = 1; //Author of command. This can typically be ignored + string command = 2; //command to request + repeated string params = 3; //Parameters are an array of strings. + string result = 4; //Result of command request. If non-numeric, it is an error message. If it's an integer, and greater than 0, it is a success (1 is default. Some commands return entity id) + bytes payload = 5; //Raw Payload to be parsed } //Entity is full of entity data. message Entity { int32 id = 1; - string name = 2; - int32 type = 3; + string name = 2; + EntityType type = 3; //0 - NPC, 1 - Client int32 hp = 4; int32 level = 5; Position position = 6; @@ -94,8 +98,9 @@ message Tint { } message Event { - OpCode op = 1; - bytes payload = 2; + OpCode op = 1; //opcode enum + bytes payload = 2; //unmarshal based on opcode + uint32 entity_id = 3; //target entity_id of event } //OP_Death @@ -294,6 +299,18 @@ message SpawnEvent { bool show_name= 100; } + +//EntityType will attempt to identify an entity to it's upper-most type by default +enum EntityType { + NPC = 0; //Inherits mob + Client = 1; //Inherits mob + Mob = 2; //Inherits entity + Mercenary = 3; //Inherits NPC + Corpse = 4; //Inherits mob + Door = 5; //Inherits entity + Object = 6; //Inherits entity +} + enum OpCode { //option allow_alias = true; OP_Unknown = 0; diff --git a/utils/nats/npcwalk/npcwalk.go b/utils/nats/npcwalk/npcwalk.go index 729540410..b04750e54 100644 --- a/utils/nats/npcwalk/npcwalk.go +++ b/utils/nats/npcwalk/npcwalk.go @@ -1,3 +1,4 @@ +//Makes a player walk around in ecommons near Guard Reskin package main import ( diff --git a/utils/nats/playersay/playersay.go b/utils/nats/playersay/playersay.go new file mode 100644 index 000000000..a9d670e01 --- /dev/null +++ b/utils/nats/playersay/playersay.go @@ -0,0 +1,245 @@ +//Makes a player say a message in local chat +package main + +import ( + "fmt" + "log" + "strconv" + "time" + + "github.com/eqemu/server/protobuf/go/eqproto" + "github.com/golang/protobuf/proto" + "github.com/nats-io/go-nats" +) + +var ( + nc *nats.Conn + err error + entities []*eqproto.Entity +) + +func main() { + + if nc, err = nats.Connect(nats.DefaultURL); err != nil { + log.Fatal(err) + } + defer nc.Close() + + zone := "ecommons" + instance := int64(0) + entities = zoneEntityList(zone, 0) + + fmt.Println(len(entities), "entities known") + + var entityID int32 + for _, entity := range entities { + if entity.Name == "Shin" { + fmt.Println("Found Shin as ID", entity.Id) + entityID = entity.Id + break + } + } + if entityID == 0 { + log.Fatal("Can't find entity!") + } + + go entityEventSubscriber(zone, instance, entityID) + zoneChannel(zone, instance, entityID, eqproto.EntityType_Client, 256, "Hello, World!") + time.Sleep(1000 * time.Second) +} + +func zoneChannel(zone string, instance int64, fromEntityID int32, fromEntityType eqproto.EntityType, chanNumber int32, message string) { + + msg := &eqproto.ChannelMessage{ + Message: message, + ChanNum: chanNumber, + FromEntityId: fromEntityID, + FromEntityType: fromEntityType, + Distance: 500, + SkipSender: true, + } + d, err := proto.Marshal(msg) + if err != nil { + log.Fatal(err) + } + channel := fmt.Sprintf("zone.%s.channel_message.in", zone) + log.Println(channel, "sending channel request", msg) + reply, err := nc.Request(channel, d, 1*time.Second) + if err != nil { + log.Println("Failed to get request response on zone channel:", err.Error()) + return + } + + err = proto.Unmarshal(reply.Data, msg) + if err != nil { + fmt.Println("Failed to unmarshal", err.Error()) + return + } + fmt.Println("Response:", msg) + return +} + +func testAttack(zone string, entityID int64, targetID int64) { + time.Sleep(10 * time.Second) + fmt.Println("10 seconds, Having", entityID, "attack", targetID) + params := []string{ + fmt.Sprintf("%d", entityID), + fmt.Sprintf("%d", targetID), //attack first element + "1", //amount of hate + } + command := "attack" + zoneCommand(zone, command, params) +} + +func zoneEntityList(zone string, instanceID int) (entities []*eqproto.Entity) { + msg := &eqproto.CommandMessage{ + Author: "xackery", + Command: "entitylist", + Params: []string{"client"}, + } + + d, err := proto.Marshal(msg) + if err != nil { + log.Fatal(err) + } + + channel := fmt.Sprintf("zone.%s.command_message.in", zone) + reply, err := nc.Request(channel, d, 1*time.Second) + if err != nil { + log.Println("Failed to get response on", channel, "", err.Error()) + return + } + + err = proto.Unmarshal(reply.Data, msg) + if err != nil { + fmt.Println("Failed to unmarshal", err.Error()) + return + } + + rootEntities := &eqproto.Entities{} + err = proto.Unmarshal([]byte(msg.Payload), rootEntities) + if err != nil { + fmt.Println("failed to unmarshal entities", err.Error(), msg) + return + } + entities = rootEntities.Entities + return +} + +func zoneCommandEntity(zone string, command string, params []string) (entityID int64) { + msg := &eqproto.CommandMessage{ + Author: "xackery", + Command: command, + Params: params, + } + d, err := proto.Marshal(msg) + if err != nil { + log.Fatal(err) + } + reply, err := nc.Request(fmt.Sprintf("zone.%s.command_message.in", zone), d, 1*time.Second) + if err != nil { + log.Println("Failed to get request response:", err.Error()) + return + } + + err = proto.Unmarshal(reply.Data, msg) + if err != nil { + fmt.Println("Failed to unmarshal", err.Error()) + return + } + fmt.Println("Response:", msg) + entityID, err = strconv.ParseInt(msg.Result, 10, 64) + if err != nil { + fmt.Println("Failed to parse response", err.Error(), msg.Result) + return + } + return +} + +func zoneCommand(zone string, command string, params []string) { + msg := &eqproto.CommandMessage{ + Author: "xackery", + Command: command, + Params: params, + } + d, err := proto.Marshal(msg) + if err != nil { + log.Fatal(err) + } + reply, err := nc.Request(fmt.Sprintf("zone.%s.command_message.in", zone), d, 1*time.Second) + if err != nil { + log.Println("Failed to get request response:", err.Error()) + return + } + + err = proto.Unmarshal(reply.Data, msg) + if err != nil { + fmt.Println("Failed to unmarshal", err.Error()) + return + } + fmt.Println("Response:", msg) + return +} + +func entityEventSubscriber(zone string, instance int64, entityID int32) { + + /*event := &eqproto.EntityEvent{ + Entity: &eqproto.Entity{ + Id: 1, + }, + } + d, err := proto.Marshal(event) + if err != nil { + log.Fatal(err) + } + if err = nc.Publish(fmt.Sprintf("zone.%s.entity.event_subscribe.all", zone), d); err != nil { + log.Println("Failed to publish event subscribe:", err.Error()) + return + }*/ + + var opCode int64 + var index int + channel := fmt.Sprintf("zone.%s.%d.entity.%d.event.out", zone, instance, entityID) + nc.Subscribe(channel, func(m *nats.Msg) { + event := &eqproto.Event{} + err = proto.Unmarshal(m.Data, event) + if err != nil { + fmt.Println("invalid event data passed", m.Data) + } + + var eventPayload proto.Message + switch event.Op { + case eqproto.OpCode_OP_ClientUpdate: + eventPayload = &eqproto.PlayerPositionUpdateEvent{} + case eqproto.OpCode_OP_Animation: + eventPayload = &eqproto.AnimationEvent{} + case eqproto.OpCode_OP_NewSpawn: + eventPayload = &eqproto.SpawnEvent{} + case eqproto.OpCode_OP_ZoneEntry: + eventPayload = &eqproto.SpawnEvent{} + case eqproto.OpCode_OP_HPUpdate: + eventPayload = &eqproto.HPEvent{} + case eqproto.OpCode_OP_MobHealth: + eventPayload = &eqproto.HPEvent{} + case eqproto.OpCode_OP_DeleteSpawn: + eventPayload = &eqproto.DeleteSpawnEvent{} + case eqproto.OpCode_OP_Damage: + eventPayload = &eqproto.DamageEvent{} + default: + return + } + err = proto.Unmarshal(event.Payload, eventPayload) + if err != nil { + fmt.Println("Invalid data passed for opcode", eqproto.OpCode(opCode), err.Error(), string(m.Data[index+1:])) + return + } + fmt.Println(m.Subject, event.Op, eventPayload) + //log.Printf("Received a message on %s: %s\n", m.Subject, string(m.Data)) + + //proto.Unmarshal(m.Data, event) + //log.Println(event.Op.String(), event.Entity, event.Target) + }) + log.Println("Subscribed to", channel, ", waiting on messages...") + + time.Sleep(500 * time.Second) +} diff --git a/world/nats_manager.cpp b/world/nats_manager.cpp index b50aa83f2..a8076cd1d 100644 --- a/world/nats_manager.cpp +++ b/world/nats_manager.cpp @@ -73,13 +73,13 @@ bool NatsManager::connect() { Log(Logs::General, Logs::NATS, "connected to %s", connection.c_str()); nats_timer.Disable(); - s = natsConnection_SubscribeSync(&channelMessageSub, conn, "world.channel_message->in"); + s = natsConnection_SubscribeSync(&channelMessageSub, conn, "world.channel_message.in"); if (s != NATS_OK) - Log(Logs::General, Logs::NATS, "world.channel_message->in: failed to subscribe: %s", nats_GetLastError(&s)); + Log(Logs::General, Logs::NATS, "world.channel_message.in: failed to subscribe: %s", nats_GetLastError(&s)); - s = natsConnection_SubscribeSync(&commandMessageSub, conn, "world.command_message->in"); + s = natsConnection_SubscribeSync(&commandMessageSub, conn, "world.command_message.in"); if (s != NATS_OK) - Log(Logs::General, Logs::NATS, "world.command_message->in: failed to subscribe: %s", nats_GetLastError(&s)); + Log(Logs::General, Logs::NATS, "world.command_message.in: failed to subscribe: %s", nats_GetLastError(&s)); return true; } @@ -99,7 +99,7 @@ void NatsManager::Process() eqproto::ChannelMessage* message = google::protobuf::Arena::CreateMessage(&the_arena); if (!message->ParseFromString(natsMsg_GetData(msg))) { - Log(Logs::General, Logs::NATS, "world.channel_message->in: failed to parse"); + Log(Logs::General, Logs::NATS, "world.channel_message.in: failed to parse"); natsMsg_Destroy(msg); continue; } @@ -116,7 +116,7 @@ void NatsManager::Process() eqproto::CommandMessage* message = google::protobuf::Arena::CreateMessage(&the_arena); if (!message->ParseFromString(natsMsg_GetData(msg))) { - Log(Logs::General, Logs::NATS, "world.command_message->in: failed to parse"); + Log(Logs::General, Logs::NATS, "world.command_message.in: failed to parse"); natsMsg_Destroy(msg); continue; } @@ -183,28 +183,6 @@ void NatsManager::SendAdminMessage(std::string adminMessage, const char* reply) Log(Logs::General, Logs::NATS, "global.admin_message.out: %s", adminMessage.c_str()); } -// SendChannelMessage will send a channel message to NATS -void NatsManager::SendChannelMessage(eqproto::ChannelMessage* message, const char* reply) { - if (!connect()) - return; - - std::string pubMessage; - if (!message->SerializeToString(&pubMessage)) { - Log(Logs::General, Logs::NATS, "world.channel_message.out: failed to serialize message to string"); - return; - } - - if (reply && strlen(reply) > 0) - s = natsConnection_Publish(conn, reply, (const void*)pubMessage.c_str(), pubMessage.length()); - else - s = natsConnection_Publish(conn, "world.channel_message.out", (const void*)pubMessage.c_str(), pubMessage.length()); - - if (s != NATS_OK) { - Log(Logs::General, Logs::NATS, "world.channel_message.out failed: %s"); - return; - } - Log(Logs::General, Logs::NATS, "world.channel_message.out: %s", message->message().c_str()); -} // SendCommandMessage will send a channel message to NATS void NatsManager::SendCommandMessage(eqproto::CommandMessage* message, const char* reply) { @@ -307,8 +285,6 @@ void NatsManager::GetChannelMessage(eqproto::ChannelMessage* message, const char if (!connect()) return; - - Log(Logs::General, Logs::NATS, "world.channel_message->in: %s", message->message().c_str()); if (message->is_emote()) { //emote message zoneserver_list.SendEmoteMessage(message->to().c_str(), message->guilddbid(), message->minstatus(), message->type(), message->message().c_str()); message->set_result("Sent message"); @@ -325,11 +301,41 @@ void NatsManager::GetChannelMessage(eqproto::ChannelMessage* message, const char if (channel < 1) channel = 5; //default to ooc zoneserver_list.SendChannelMessage(tmpname, 0, channel, message->language(), message->message().c_str()); - message->set_result("Sent message"); + message->set_result("1"); SendChannelMessage(message, reply); return; } + +// SendChannelMessage will send a channel message to NATS +void NatsManager::SendChannelMessage(eqproto::ChannelMessage* message, const char* reply) { + if (!connect()) + return; + + std::string pubMessage; + if (!message->SerializeToString(&pubMessage)) { + Log(Logs::General, Logs::NATS, "world.channel_message.out: failed to serialize message to string"); + return; + } + + if (reply) { + s = natsConnection_Publish(conn, reply, (const void*)pubMessage.c_str(), pubMessage.length()); + } + else { + s = natsConnection_Publish(conn, "world.channel_message.out", (const void*)pubMessage.c_str(), pubMessage.length()); + } + + if (s != NATS_OK) { + Log(Logs::General, Logs::NATS, "world.channel_message.out failed: %s", nats_GetLastError(&s)); + return; + } + + if (reply) + Log(Logs::General, Logs::NATS, "world.channel_message.in: %s (%s)", message->message().c_str(), message->result().c_str()); + else + Log(Logs::General, Logs::NATS, "world.channel_message.out: %s", message->message().c_str()); +} + void NatsManager::Load() { if (!connect()) diff --git a/zone/entity.cpp b/zone/entity.cpp index 8c362375f..e54042d5a 100644 --- a/zone/entity.cpp +++ b/zone/entity.cpp @@ -4879,16 +4879,3 @@ void EntityList::ReloadMerchants() { } } } - - -std::map EntityList::ListNPCs() -{ - std::map npcs; - auto it = npc_list.begin(); - while (it != npc_list.end()) { - NPC *n = it->second; - npcs[n->id] = n; - ++it; - } - return npcs; -} \ No newline at end of file diff --git a/zone/entity.h b/zone/entity.h index 3545bd979..4b3ba15f0 100644 --- a/zone/entity.h +++ b/zone/entity.h @@ -216,7 +216,7 @@ public: return it->second; return nullptr; } - std::map ListNPCs(); + Doors *GetDoorsByDoorID(uint32 id); Doors *GetDoorsByDBID(uint32 id); void RemoveAllCorpsesByCharID(uint32 charid); diff --git a/zone/nats_manager.cpp b/zone/nats_manager.cpp index 91eb4c960..c0f7487b0 100644 --- a/zone/nats_manager.cpp +++ b/zone/nats_manager.cpp @@ -1,6 +1,6 @@ #include "entity.h" #include "mob.h" -//#include "client.h" //map error +#include "client.h" #include "event_codes.h" #include "nats.h" #include "zone_config.h" @@ -13,6 +13,7 @@ #include "../common/string_util.h" #ifndef PROTO_H #define PROTO_H +#undef new //needed for linux compile #include "../common/message.pb.h" #endif #include @@ -51,196 +52,388 @@ void NatsManager::Process() for (int count = 0; (s == NATS_OK) && count < 5; count++) { s = natsSubscription_NextMsg(&msg, zoneCommandMessageSub, 1); - if (s != NATS_OK) { - s = natsSubscription_NextMsg(&msg, zoneInstanceCommandMessageSub, 1); - if (s != NATS_OK) { - break; - } - } + if (s != NATS_OK) + break; eqproto::CommandMessage* message = google::protobuf::Arena::CreateMessage(&the_arena); - if (!message->ParseFromString(natsMsg_GetData(msg))) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.command_message.in: failed to parse", subscribedZoneName.c_str(), subscribedZoneInstance); + Log(Logs::General, Logs::NATS, "zone.%s.command_message.in: failed to parse", subscribedZoneName.c_str()); natsMsg_Destroy(msg); continue; } - - if (message->command().compare("npctypespawn") == 0) { - if (message->params_size() < 2) { - message->set_result("Usage: !npctypespawn ."); - } else { - - uint32 npctypeid = atoi(message->params(0).c_str()); - uint32 factionid = atoi(message->params(1).c_str()); - float x = atof(message->params(2).c_str()); - float y = atof(message->params(3).c_str()); - float z = atof(message->params(4).c_str()); - float h = atof(message->params(5).c_str()); - auto position = glm::vec4(x, y, z, h); - const NPCType* tmp = 0; - - /*if (!(tmp = database.LoadNPCTypesData(npctypeid))) { - message->set_result(StringFormat("NPC Type %i not found", npctypeid)); - } else { - //tmp->fixedZ = 1; - - auto npc = new NPC(tmp, 0, position, FlyMode3); - if (npc && factionid >0) - npc->SetNPCFactionID(factionid); - npc->AddLootTable(); - entity_list.AddNPC(npc); - message->set_result("Created NPC successfully."); - } - */ - } - } - - if (message->command().compare("npctypespawn") == 0) { - if (message->params_size() < 5) { - message->set_result("Usage: npctypespawn name race level material hp gender class priweapon secweapon merchantid bodytype."); - } - else { - - float x = atof(message->params(0).c_str()); - float y = atof(message->params(1).c_str()); - float z = atof(message->params(2).c_str()); - float h = atof(message->params(3).c_str()); - auto position = glm::vec4(x, y, z, h); - - std::string argumentString; - for (int i = 4; i < message->params_size(); i++) { - argumentString.append(StringFormat(" %s", message->params(i).c_str())); - } - - NPC* npc = NPC::SpawnNPC(argumentString.c_str(), position, NULL); - if (!npc) { - message->set_result("Format: #spawn name race level material hp gender class priweapon secweapon merchantid bodytype - spawns a npc those parameters."); - } - else { - message->set_result(StringFormat("%u", npc->GetID())); - } - } - } - - if (message->command().compare("moveto") == 0) { - if (message->params_size() < 5) { - message->set_result("Usage: moveto ."); - } - else { - uint16 entityid = atoi(message->params(0).c_str()); - float x = atof(message->params(1).c_str()); - float y = atof(message->params(2).c_str()); - float z = atof(message->params(3).c_str()); - float h = atof(message->params(4).c_str()); - auto position = glm::vec4(x, y, z, h); - - auto npc = entity_list.GetNPCByID(entityid); - if (!npc) { - message->set_result("Invalid entity ID passed, or not an npc, etc"); - } - else { - npc->MoveTo(position, true); - message->set_result("OK"); - } - } - } - - if (message->command().compare("attack") == 0) { - if (message->params_size() < 3) { - message->set_result("Usage: attack ."); - } - else { - uint16 entityID = atoi(message->params(0).c_str()); - uint16 targetEntityID = atoi(message->params(1).c_str()); - uint32 hateAmount = atoi(message->params(2).c_str()); - - auto npc = entity_list.GetNPCByID(entityID); - if (!npc) { - message->set_result("Invalid entity ID passed, or not an npc, etc"); - } - else { - auto mob = entity_list.GetMobID(targetEntityID); - if (!mob) { - message->set_result("Invalid target entitiy ID passed, or not a mob, etc"); - } - else { - npc->AddToHateList(mob, hateAmount); - message->set_result("OK"); - } - } - } - } - - if (message->command().compare("entitylist") == 0) { - std::string entityPayload; - if (message->params_size() < 1) { - message->set_result("Usage: entitylist ."); - } - else { - eqproto::Entities* entities = google::protobuf::Arena::CreateMessage(&the_arena); - if (message->params(0).compare("npc") == 0) { - auto npcs = entity_list.ListNPCs(); - auto it = npcs.begin(); - for (const auto &entry : npcs) { - auto entity = entities->add_entities(); - entity->set_id(entry.second->GetID()); - entity->set_type(1); - entity->set_name(entry.second->GetName()); - } - - if (!entities->SerializeToString(&entityPayload)) { - message->set_result("Failed to serialized entitiy result"); - } - else { - message->set_result("OK"); - message->set_payload(entityPayload.c_str()); - } - } - /*else if (message->params(0).compare("client") == 0) { - auto clients = entity_list.ListClients(); - auto it = clients.begin(); - for (const auto &entry : clients) { - auto entity = entities->add_entities(); - entity->set_id(entry.second->GetID()); - entity->set_type(0); - entity->set_name(entry.second->GetName()); - } - - if (!entities->SerializeToString(&entityMessage)) { - message->set_result("Failed to serialized entitiy result"); - } - else { - message->set_result(entityMessage.c_str()); - } - }*/ - else { - message->set_result("Usage: entitylist ."); - } - } - } - - if (message->result().length() < 1) { - message->set_result("Failed to parse command."); - Log(Logs::General, Logs::NATS, "zone.%s.%d.command_message.in: failed to parse command", subscribedZoneName.c_str(), subscribedZoneInstance); - natsMsg_Destroy(msg); - continue; - } - - if (!message->SerializeToString(&pubMessage)) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.command_message.in: failed to serialize to string", subscribedZoneName.c_str(), subscribedZoneInstance); - natsMsg_Destroy(msg); - continue; - } - - s = natsConnection_Publish(conn, natsMsg_GetReply(msg), (const void*)pubMessage.c_str(), pubMessage.length()); - if (s != NATS_OK) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.command_message.in: failed to publish: %s", subscribedZoneName.c_str(), subscribedZoneInstance, nats_GetLastError(&s)); - natsMsg_Destroy(msg); - continue; - } - Log(Logs::General, Logs::NATS, "zone.%s.%d.command_message.in: %s (%s)", subscribedZoneName.c_str(), subscribedZoneInstance, message->command().c_str(), message->result().c_str()); + GetCommandMessage(message, natsMsg_GetReply(msg)); + natsMsg_Destroy(msg); } + + s = NATS_OK; + for (int count = 0; (s == NATS_OK) && count < 5; count++) + { + s = natsSubscription_NextMsg(&msg, zoneInstanceCommandMessageSub, 1); + if (s != NATS_OK) + break; + + eqproto::CommandMessage* message = google::protobuf::Arena::CreateMessage(&the_arena); + if (!message->ParseFromString(natsMsg_GetData(msg))) { + Log(Logs::General, Logs::NATS, "zone.%s.%dcommand_message.in: failed to parse", subscribedZoneName.c_str(), subscribedZoneInstance); + natsMsg_Destroy(msg); + continue; + } + GetCommandMessage(message, natsMsg_GetReply(msg)); + natsMsg_Destroy(msg); + } + + s = NATS_OK; + for (int count = 0; (s == NATS_OK) && count < 5; count++) + { + s = natsSubscription_NextMsg(&msg, zoneChannelMessageSub, 1); + if (s != NATS_OK) + break; + + eqproto::ChannelMessage* message = google::protobuf::Arena::CreateMessage(&the_arena); + if (!message->ParseFromString(natsMsg_GetData(msg))) { + Log(Logs::General, Logs::NATS, "zone.%s.channel_message.in: failed to parse", subscribedZoneName.c_str()); + natsMsg_Destroy(msg); + continue; + } + GetChannelMessage(message, natsMsg_GetReply(msg)); + natsMsg_Destroy(msg); + } + + s = NATS_OK; + for (int count = 0; (s == NATS_OK) && count < 5; count++) + { + s = natsSubscription_NextMsg(&msg, zoneInstanceChannelMessageSub, 1); + if (s != NATS_OK) + break; + + eqproto::ChannelMessage* message = google::protobuf::Arena::CreateMessage(&the_arena); + if (!message->ParseFromString(natsMsg_GetData(msg))) { + Log(Logs::General, Logs::NATS, "zone.%s.%d.channel_message.in: failed to parse", subscribedZoneName.c_str(), subscribedZoneInstance); + natsMsg_Destroy(msg); + continue; + } + GetChannelMessage(message, natsMsg_GetReply(msg)); + natsMsg_Destroy(msg); + } +} + +// GetChannelMessage is when a 3rd party app sends a channel message via NATS. +void NatsManager::GetChannelMessage(eqproto::ChannelMessage* message, const char* reply) { + if (!connect()) + return; + + if (message->from_entity_id() < 1) { + message->set_result("from_entity_id must be set to send zone channel messages."); + SendChannelMessage(message, reply); + return; + } + + + auto mob = entity_list.GetMobID(message->from_entity_id()); + if (!mob) { + message->set_result("from_entity_id not found"); + SendChannelMessage(message, reply); + return; + } + + if (message->distance() > 0) + entity_list.MessageClose(mob, message->skip_sender(), message->distance(), message->chan_num(), message->message().c_str()); + else + mob->Message(message->chan_num(), message->message().c_str()); + + message->set_result("1"); + SendChannelMessage(message, reply); + return; +} + + +// SendChannelMessage will send a channel message to NATS +void NatsManager::SendChannelMessage(eqproto::ChannelMessage* message, const char* reply) { + if (!connect()) + return; + + std::string pubMessage; + if (!message->SerializeToString(&pubMessage)) { + Log(Logs::General, Logs::NATS, "world.channel_message.out: failed to serialize message to string"); + return; + } + + if (reply) + s = natsConnection_Publish(conn, reply, (const void*)pubMessage.c_str(), pubMessage.length()); + else + s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.channel_message.out", subscribedZoneName.c_str(), subscribedZoneInstance).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); + + + if (s != NATS_OK) { + Log(Logs::General, Logs::NATS, "world.channel_message.out failed: %s", nats_GetLastError(&s)); + return; + } + + if (reply) + Log(Logs::General, Logs::NATS, "zone.%s.%d.channel_message.in: %s (%s)", subscribedZoneName.c_str(), subscribedZoneInstance, message->message().c_str(), message->result().c_str()); + else + Log(Logs::General, Logs::NATS, "zone.%s.%d.channel_message.out: %s", subscribedZoneName.c_str(), subscribedZoneInstance, message->message().c_str()); +} + + +// GetCommandMessage is used to process a command message +void NatsManager::GetCommandMessage(eqproto::CommandMessage* message, const char* reply) { + if (!connect()) + return; + + if (message->command().compare("npctypespawn") == 0) { + if (message->params_size() < 2) { + message->set_result("Format: npctypespawn "); + SendCommandMessage(message, reply); + return; + } + + float x = atof(message->params(0).c_str()); + float y = atof(message->params(1).c_str()); + float z = atof(message->params(2).c_str()); + float h = atof(message->params(3).c_str()); + auto position = glm::vec4(x, y, z, h); + + uint32 npctypeid = atoi(message->params(4).c_str()); + uint32 factionid = atoi(message->params(5).c_str()); + const NPCType* tmp = 0; + if (!(tmp = database.LoadNPCTypesData(npctypeid))) { + message->set_result(StringFormat("NPC Type %i not found", npctypeid)); + SendCommandMessage(message, reply); + return; + } + + //tmp->fixedZ = 1; + + auto npc = new NPC(tmp, 0, position, FlyMode3); + if (!npc) { + message->set_result("failed to instantiate npc"); + SendCommandMessage(message, reply); + return; + } + + if (factionid > 0) + npc->SetNPCFactionID(factionid); + npc->AddLootTable(); + entity_list.AddNPC(npc); + message->set_result(StringFormat("%u", npc->GetID())); + SendCommandMessage(message, reply); + return; + } + + if (message->command().compare("spawn") == 0) { + if (message->params_size() < 5) { + message->set_result("Format: spawn - spawns a npc those parameters."); + SendCommandMessage(message, reply); + return; + } + + float x = atof(message->params(0).c_str()); + float y = atof(message->params(1).c_str()); + float z = atof(message->params(2).c_str()); + float h = atof(message->params(3).c_str()); + auto position = glm::vec4(x, y, z, h); + + std::string argumentString; + for (int i = 4; i < message->params_size(); i++) { + argumentString.append(StringFormat(" %s", message->params(i).c_str())); + } + + NPC* npc = NPC::SpawnNPC(argumentString.c_str(), position, NULL); + if (!npc) { + message->set_result("Format: spawn - spawns a npc those parameters."); + SendCommandMessage(message, reply); + return; + } + + message->set_result(StringFormat("%u", npc->GetID())); + SendCommandMessage(message, reply); + return; + } + + if (message->command().compare("moveto") == 0) { + if (message->params_size() < 5) { + message->set_result("Usage: moveto ."); + SendCommandMessage(message, reply); + return; + } + + uint16 entityid = atoi(message->params(0).c_str()); + float x = atof(message->params(1).c_str()); + float y = atof(message->params(2).c_str()); + float z = atof(message->params(3).c_str()); + float h = atof(message->params(4).c_str()); + auto position = glm::vec4(x, y, z, h); + + auto npc = entity_list.GetNPCByID(entityid); + if (!npc) { + message->set_result("Invalid entity ID passed, or not an npc, etc"); + SendCommandMessage(message, reply); + return; + } + + npc->MoveTo(position, true); + message->set_result("1"); + SendCommandMessage(message, reply); + return; + } + + if (message->command().compare("attack") == 0) { + if (message->params_size() < 3) { + message->set_result("Usage: attack ."); + SendCommandMessage(message, reply); + return; + } + uint16 entityID = atoi(message->params(0).c_str()); + uint16 targetEntityID = atoi(message->params(1).c_str()); + uint32 hateAmount = atoi(message->params(2).c_str()); + + auto npc = entity_list.GetNPCByID(entityID); + if (!npc) { + message->set_result("Invalid entity ID passed, or not an npc, etc"); + SendCommandMessage(message, reply); + return; + } + + auto mob = entity_list.GetMobID(targetEntityID); + if (!mob) { + message->set_result("Invalid target entitiy ID passed, or not a mob, etc"); + SendCommandMessage(message, reply); + return; + } + npc->AddToHateList(mob, hateAmount); + message->set_result("1"); + SendCommandMessage(message, reply); + return; + } + + if (message->command().compare("entitylist") == 0) { + std::string entityPayload; + if (message->params_size() < 1) { + message->set_result("Usage: entitylist . Types: npc, client, mob, mercenary, corpse, door, object"); + SendCommandMessage(message, reply); + return; + } + + eqproto::Entities* entities = google::protobuf::Arena::CreateMessage(&the_arena); + if (message->params(0).compare("npc") == 0) { + + auto npcs = entity_list.GetNPCList(); + auto it = npcs.begin(); + for (const auto &entry : npcs) { + if (entry.second == nullptr) + continue; + auto npc = entry.second; + auto entity = entities->add_entities(); + entity->set_id(npc->GetID()); + entity->set_type(eqproto::EntityType::NPC); + entity->set_name(npc->GetName()); + } + + if (!entities->SerializeToString(&entityPayload)) { + message->set_result("Failed to serialize entitiy result"); + SendCommandMessage(message, reply); + return; + } + + message->set_result("1"); + message->set_payload(entityPayload.c_str()); + SendCommandMessage(message, reply); + return; + } + else if (message->params(0).compare("client") == 0) { + auto clients = entity_list.GetClientList(); + auto it = clients.begin(); + for (const auto &entry : clients) { + if (entry.second == nullptr) + continue; + auto client = entry.second; + auto entity = entities->add_entities(); + + entity->set_type(eqproto::EntityType::Client); + entity->set_name(client->GetName()); + entity->set_id(client->GetID()); + } + + if (!entities->SerializeToString(&entityPayload)) { + message->set_result("Failed to serialize entitiy result"); + SendCommandMessage(message, reply); + return; + } + message->set_result("1"); + message->set_payload(entityPayload.c_str()); + SendCommandMessage(message, reply); + return; + } + else if (message->params(0).compare("mob") == 0) { + auto mobs = entity_list.GetMobList(); + auto it = mobs.begin(); + for (const auto &entry : mobs) { + if (entry.second == nullptr) + continue; + + auto mob = entry.second; + auto entity = entities->add_entities(); + entity->set_type(eqproto::EntityType::Mob); + if (mob->IsClient()) + entity->set_type(eqproto::EntityType::Client); + if (mob->IsNPC()) + entity->set_type(eqproto::EntityType::NPC); + if (mob->IsMerc()) + entity->set_type(eqproto::EntityType::Mercenary); + + entity->set_id(mob->GetID()); + entity->set_name(mob->GetName()); + } + + if (!entities->SerializeToString(&entityPayload)) { + message->set_result("Failed to serialize entitiy result"); + SendCommandMessage(message, reply); + return; + } + message->set_result("1"); + message->set_payload(entityPayload.c_str()); + SendCommandMessage(message, reply); + return; + } + message->set_result("Usage: entitylist . Types: npc, client, mob, mercenary, corpse, door, object"); + SendCommandMessage(message, reply); + return; + } + + message->set_result("Failed to parse command."); + SendCommandMessage(message, reply); + return; +} + + +// SendCommandMessage will send a channel message to NATS +void NatsManager::SendCommandMessage(eqproto::CommandMessage* message, const char* reply) { + if (!connect()) + return; + + if (message->result().length() == 0) + message->set_result("Failed to parse command."); + + + std::string pubMessage; + if (!message->SerializeToString(&pubMessage)) { + Log(Logs::General, Logs::NATS, "zone.%s.%d.command_message.in: failed to serialize to string", subscribedZoneName.c_str(), subscribedZoneInstance); + return; + } + + if (reply) + s = natsConnection_Publish(conn, reply, (const void*)pubMessage.c_str(), pubMessage.length()); + else + s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.command_message.out", subscribedZoneName.c_str(), subscribedZoneInstance).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); + + + if (s != NATS_OK) { + Log(Logs::General, Logs::NATS, "zone.%s.%d.command_message.in: failed: %s", subscribedZoneName.c_str(), subscribedZoneInstance, nats_GetLastError(&s)); + return; + } + + Log(Logs::General, Logs::NATS, "zone.%s.%d.command_message.in: %s (%s)", subscribedZoneName.c_str(), subscribedZoneInstance, message->command().c_str(), message->result().c_str()); } //Unregister is called when a zone is being put to sleep or being swapped @@ -286,6 +479,24 @@ void NatsManager::Unregister() return; } +void NatsManager::SendEvent(eqproto::OpCode op, uint32 entity_id, std::string pubMessage) { + + eqproto::Event* finalEvent = google::protobuf::Arena::CreateMessage(&the_arena); + finalEvent->set_payload(pubMessage.c_str()); + finalEvent->set_op(op); + finalEvent->set_entity_id(entity_id); + + if (!finalEvent->SerializeToString(&pubMessage)) { + Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); + return; + } + + s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.entity.%d.event.out", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); + if (s != NATS_OK) + Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to send: %s", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op, nats_GetLastError(&s)); + +} + void NatsManager::ZoneSubscribe(const char* zonename, uint32 instance) { if (strcmp(subscribedZoneName.c_str(), zonename) == 0) return; @@ -404,89 +615,6 @@ void NatsManager::Load() return; } -/* -void NatsManager::OnEntityEvent(const EmuOpcode op, Entity *ent, Entity *target) { - if (ent == NULL) return; - if (!isEntityEventAllEnabled && !isEntitySubscribed(ent->GetID())) { - return; - } - - - if (!conn) { - Log(Logs::General, Logs::NATS, "OnChannelMessage failed, no connection to NATS"); - return; - } - - eqproto::EntityEvent event; - event->set_op(eqproto::OpCode(op)); - eqproto::Entity entity; - entity.set_id(ent->GetID()); - entity.set_name(ent->GetName()); - - if (ent->IsClient()) { - entity.set_type(1); - } - else if (ent->IsNPC()) { - entity.set_type(2); - } - - auto position = eqproto::Position(); - if (ent->IsMob()) { - auto mob = ent->CastToMob(); - entity.set_hp(mob->GetHP()); - entity.set_level(mob->GetLevel()); - entity.set_name(mob->GetName()); - position.set_x(mob->GetX()); - position.set_y(mob->GetY()); - position.set_z(mob->GetZ()); - position.set_h(mob->GetHeading()); - entity.set_race(mob->GetRace()); - entity.set_class_(mob->GetClass()); - } - - auto targetEntity = eqproto::Entity(); - auto targetPosition = eqproto::Position(); - if (target != NULL && target->IsMob()) { - if (target->IsClient()) { - targetEntity.set_type(1); - } - else if (target->IsNPC()) { - targetEntity.set_type(2); - } - auto mob = target->CastToMob(); - targetEntity.set_hp(mob->GetHP()); - targetEntity.set_level(mob->GetLevel()); - targetEntity.set_name(mob->GetName()); - targetPosition.set_x(mob->GetX()); - targetPosition.set_y(mob->GetY()); - targetPosition.set_z(mob->GetZ()); - targetPosition.set_h(mob->GetHeading()); - targetEntity.set_race(mob->GetRace()); - targetEntity.set_class_(mob->GetClass()); - } - - entity.set_allocated_position(&position); - targetEntity.set_allocated_position(&targetPosition); - event->set_allocated_entity(&entity); - event->set_allocated_target(&targetEntity); - - - std::string pubMessage; - bool isSerialized = event->SerializeToString(&pubMessage); - if (!isSerialized) Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); - Log(Logs::General, Logs::NATS, "Event: %d", op); - - s = natsConnection_Publish(conn, StringFormat("zone.%s.entity.event->%d", subscribedZonename.c_str(), ent->GetID()).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); - if (s != NATS_OK) Log(Logs::General, Logs::NATS, "Failed to send EntityEvent"); - entity.release_name(); - targetEntity.release_name(); - entity.release_position(); - targetEntity.release_position(); - event->release_entity(); - event->release_target(); - return; -}*/ - bool NatsManager::isEntitySubscribed(const uint16 ID) { if (!connect()) return false; @@ -505,7 +633,6 @@ void NatsManager::OnDeathEvent(Death_Struct* d) { return; auto op = eqproto::OP_Death; - std::string pubMessage; eqproto::DeathEvent* event = google::protobuf::Arena::CreateMessage(&the_arena); @@ -521,17 +648,8 @@ void NatsManager::OnDeathEvent(Death_Struct* d) { return; } - eqproto::Event* finalEvent = google::protobuf::Arena::CreateMessage(&the_arena); - - finalEvent->set_payload(pubMessage.c_str()); - finalEvent->set_op(op); - if (!finalEvent->SerializeToString(&pubMessage)) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, d->spawn_id, op); - return; - } - s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.entity.%d.event.out", subscribedZoneName.c_str(), subscribedZoneInstance, d->spawn_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); - if (s != NATS_OK) - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to send: %s", subscribedZoneName.c_str(), subscribedZoneInstance, d->spawn_id, op, nats_GetLastError(&s)); + SendEvent(op, d->spawn_id, pubMessage); + SendEvent(op, d->killer_id, pubMessage); } @@ -561,17 +679,6 @@ void NatsManager::OnChannelMessageEvent(uint32 entity_id, ChannelMessage_Struct* return; } - eqproto::Event* finalEvent = google::protobuf::Arena::CreateMessage(&the_arena); - - finalEvent->set_payload(pubMessage.c_str()); - finalEvent->set_op(eqproto::OP_ChannelMessage); - if (!finalEvent->SerializeToString(&pubMessage)) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.channel_message.out: failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance); - return; - } - s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.channel_message.out", subscribedZoneName.c_str(), subscribedZoneInstance).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); - if (s != NATS_OK) - Log(Logs::General, Logs::NATS, "Failed to send EntityEvent"); } void NatsManager::OnEntityEvent(const EmuOpcode op, uint32 entity_id, uint32 target_id) { @@ -598,24 +705,20 @@ void NatsManager::OnEntityEvent(const EmuOpcode op, uint32 entity_id, uint32 tar eqproto::Event* finalEvent = google::protobuf::Arena::CreateMessage(&the_arena); finalEvent->set_payload(pubMessage.c_str()); + + auto eqop = eqproto::OP_Camp; if (op == OP_Camp) { - finalEvent->set_op(eqproto::OP_Camp); + eqop = eqproto::OP_Camp; } else if (op == OP_Assist) { - finalEvent->set_op(eqproto::OP_Assist); + eqop = eqproto::OP_Assist; } else { Log(Logs::General, Logs::NATS, "unhandled op type passed: %i", op); return; } - if (!finalEvent->SerializeToString(&pubMessage)) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); - return; - } - s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.entity.%d.event.out", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); - if (s != NATS_OK) - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to send: %s", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op, nats_GetLastError(&s)); - + SendEvent(eqop, entity_id, pubMessage); + SendEvent(eqop, target_id, pubMessage); } @@ -744,25 +847,16 @@ void NatsManager::OnSpawnEvent(const EmuOpcode op, uint32 entity_id, Spawn_Struc return; } - eqproto::Event* finalEvent = google::protobuf::Arena::CreateMessage(&the_arena); - finalEvent->set_payload(pubMessage.c_str()); - if (op == OP_ZoneEntry) - finalEvent->set_op(eqproto::OP_ZoneEntry); - else if (op == OP_NewSpawn) - finalEvent->set_op(eqproto::OP_NewSpawn); + auto eqop = eqproto::OP_ZoneEntry; + if (op == OP_ZoneEntry) + eqop = eqproto::OP_ZoneEntry; + else if (op == OP_NewSpawn) + eqop = eqproto::OP_NewSpawn; else { Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) unhandled opcode passed", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); return; } - - if (!finalEvent->SerializeToString(&pubMessage)) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); - return; - } - s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.entity.%d.event.out", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); - if (s != NATS_OK) - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to send: %s", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op, nats_GetLastError(&s)); - + SendEvent(eqop, entity_id, pubMessage); } @@ -790,18 +884,8 @@ void NatsManager::OnWearChangeEvent(uint32 entity_id, WearChange_Struct *wc) { Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); return; } - eqproto::Event* finalEvent = google::protobuf::Arena::CreateMessage(&the_arena); - finalEvent->set_payload(pubMessage.c_str()); - finalEvent->set_op(op); - - if (!finalEvent->SerializeToString(&pubMessage)) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); - return; - } - s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.entity.%d.event.out", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); - if (s != NATS_OK) - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to send: %s", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op, nats_GetLastError(&s)); + SendEvent(op, entity_id, pubMessage); } void NatsManager::OnDeleteSpawnEvent(uint32 entity_id, DeleteSpawn_Struct *ds) { @@ -823,18 +907,7 @@ void NatsManager::OnDeleteSpawnEvent(uint32 entity_id, DeleteSpawn_Struct *ds) { Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); return; } - - eqproto::Event* finalEvent = google::protobuf::Arena::CreateMessage(&the_arena); - finalEvent->set_payload(pubMessage.c_str()); - finalEvent->set_op(op); - if (!finalEvent->SerializeToString(&pubMessage)) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); - return; - } - s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.entity.%d.event.out", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); - if (s != NATS_OK) - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to send: %s", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op, nats_GetLastError(&s)); - + SendEvent(op, entity_id, pubMessage); } void NatsManager::OnHPEvent(const EmuOpcode op, uint32 entity_id, uint32 cur_hp, uint32 max_hp) { @@ -858,25 +931,16 @@ void NatsManager::OnHPEvent(const EmuOpcode op, uint32 entity_id, uint32 cur_hp, Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); return; } - eqproto::Event* finalEvent = google::protobuf::Arena::CreateMessage(&the_arena); - finalEvent->set_payload(pubMessage.c_str()); - if (op == OP_MobHealth) - finalEvent->set_op(eqproto::OP_MobHealth); - else if (op == OP_HPUpdate) - finalEvent->set_op(eqproto::OP_HPUpdate); + auto eqop = eqproto::OP_MobHealth; + if (op == OP_MobHealth) + eqop = eqproto::OP_MobHealth; + else if (op == OP_HPUpdate) + eqop = eqproto::OP_HPUpdate; else { Log(Logs::General, Logs::NATS, "unhandled op type passed: %i", op); return; } - - if (!finalEvent->SerializeToString(&pubMessage)) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); - return; - } - s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.entity.%d.event.out", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); - if (s != NATS_OK) - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to send: %s", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op, nats_GetLastError(&s)); - + SendEvent(eqop, entity_id, pubMessage); } void NatsManager::OnDamageEvent(uint32 entity_id, CombatDamage_Struct *cd) { @@ -905,17 +969,8 @@ void NatsManager::OnDamageEvent(uint32 entity_id, CombatDamage_Struct *cd) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; } - eqproto::Event* finalEvent = google::protobuf::Arena::CreateMessage(&the_arena); - finalEvent->set_payload(pubMessage.c_str()); - finalEvent->set_op(op); - if (!finalEvent->SerializeToString(&pubMessage)) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); - return; - } - s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.entity.%d.event.out", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); - if (s != NATS_OK) - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to send: %s", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op, nats_GetLastError(&s)); + SendEvent(op, entity_id, pubMessage); } void NatsManager::OnClientUpdateEvent(uint32 entity_id, PlayerPositionUpdateServer_Struct * spu) { @@ -949,18 +1004,8 @@ void NatsManager::OnClientUpdateEvent(uint32 entity_id, PlayerPositionUpdateServ Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); return; } - eqproto::Event* finalEvent = google::protobuf::Arena::CreateMessage(&the_arena); - finalEvent->set_payload(pubMessage.c_str()); - finalEvent->set_op(op); - - if (!finalEvent->SerializeToString(&pubMessage)) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); - return; - } - s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.entity.%d.event.out", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); - if (s != NATS_OK) - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to send: %s", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op, nats_GetLastError(&s)); + SendEvent(op, entity_id, pubMessage); } @@ -985,17 +1030,5 @@ void NatsManager::OnAnimationEvent(uint32 entity_id, Animation_Struct *anim) { Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); return; } - eqproto::Event* finalEvent = google::protobuf::Arena::CreateMessage(&the_arena); - - finalEvent->set_payload(pubMessage.c_str()); - finalEvent->set_op(op); - - - if (!finalEvent->SerializeToString(&pubMessage)) { - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to serialize message to string", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op); - return; - } - s = natsConnection_Publish(conn, StringFormat("zone.%s.%d.entity.%d.event.out", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length()); - if (s != NATS_OK) - Log(Logs::General, Logs::NATS, "zone.%s.%d.entity.%d.event.out: (OP: %d) failed to send: %s", subscribedZoneName.c_str(), subscribedZoneInstance, entity_id, op, nats_GetLastError(&s)); + SendEvent(op, entity_id, pubMessage); } \ No newline at end of file diff --git a/zone/nats_manager.h b/zone/nats_manager.h index 5175b125c..e683faeba 100644 --- a/zone/nats_manager.h +++ b/zone/nats_manager.h @@ -1,13 +1,19 @@ #ifndef _NATS_H #define _NATS_H -#include "nats.h" -#include "event_codes.h" -#include "entity.h" -#include "mob.h" +#include "nats.h" +//#include "event_codes.h" +//#include "entity.h" +//#include "mob.h" #include "../common/opcodemgr.h" -#include "../common/global_define.h" -#include "../common/types.h" +//#include "../common/global_define.h" +//#include "../common/types.h" +#undef New //Needed for MSVC compile +#undef Move //Needed for linux compile +#ifndef PROTO_H +#define PROTO_H +#include "../common/message.pb.h" +#endif class NatsManager { @@ -18,6 +24,13 @@ public: void Unregister(); void ZoneSubscribe(const char * zonename, uint32 instance); void Load(); + void GetChannelMessage(eqproto::ChannelMessage* message, const char* reply = nullptr); + void SendChannelMessage(eqproto::ChannelMessage* message, const char* reply = nullptr); + void GetCommandMessage(eqproto::CommandMessage* message, const char* reply = nullptr); + void SendCommandMessage(eqproto::CommandMessage* message, const char* reply = nullptr); + void SendAdminMessage(std::string adminMessage); + void SendEvent(eqproto::OpCode op, uint32 entity_id, std::string pubMessage); + void OnChannelMessageEvent(uint32 entity_id, ChannelMessage_Struct * cm); void OnEntityEvent(const EmuOpcode op, uint32 entity_id, uint32 target_id); void OnSpawnEvent(const EmuOpcode op, uint32 entity_id, Spawn_Struct * spawn); @@ -27,8 +40,8 @@ public: void OnDamageEvent(uint32 entity_id, CombatDamage_Struct * cd); void OnClientUpdateEvent(uint32 entity_id, PlayerPositionUpdateServer_Struct * spu); void OnAnimationEvent(uint32 entity_id, Animation_Struct * anim); - void OnDeathEvent(Death_Struct * d); - void SendAdminMessage(std::string adminMessage); + void OnDeathEvent(Death_Struct * d); + protected: bool connect(); Timer nats_timer; diff --git a/zone/zone.h b/zone/zone.h index e55aa93f1..49f094262 100644 --- a/zone/zone.h +++ b/zone/zone.h @@ -72,7 +72,7 @@ struct item_tick_struct { }; class Client; -class Map; +//class Map; //Unused? Needed to uncomment for NATS class Mob; class PathManager; class WaterMap;