Nats initial commit

This commit is contained in:
Xackery 2018-02-10 23:42:38 -08:00
parent 0b97db9fd2
commit c69b9a95b7
42 changed files with 27943 additions and 1082 deletions

22
.gitignore vendored
View File

@ -23,17 +23,19 @@ CMakeFiles
Makefile
cmake_install.cmake
install_manifest.txt
Build/
build/
Build32/
build32/
Build64/
build64/
Build_32/
build_32/
Build_64/
build_64/
[Bb]uild/
[Bb]uild32/
[Bb]uild64/
[Bb]uild_32/
[Bb]uild_64/
deploy/server/
x64/
x86/
log/
logs/
# Proto
protobuf/csharp/*
protobuf/go/*
protobuf/java/*
protobuf/python/*

View File

@ -52,7 +52,25 @@ IF(MSVC OR MINGW)
ENDIF(CMAKE_CL_64)
ENDIF(MSVC OR MINGW)
IF(MSVC)
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/deploy/server")
# include dirs are universal
SET(NATS_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/nats")
SET(PROTOBUF_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/protobuf")
SET(NATS_INCLUDE_DIR "${NATS_ROOT}/include")
SET(PROTOBUF_INCLUDE_DIR "${PROTOBUF_ROOT}/include")
IF(MSVC)
foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG )
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "${CMAKE_CURRENT_SOURCE_DIR}/deploy/server" )
set( CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "${CMAKE_CURRENT_SOURCE_DIR}/deploy/server" )
set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "${CMAKE_CURRENT_SOURCE_DIR}/deploy/server" )
endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES )
#Set our default locations for zlib/mysql based on x86/x64
IF(CMAKE_CL_64)
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x64")
@ -67,12 +85,16 @@ IF(MSVC)
ELSE()
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/x64/Release/v110/dynamic")
ENDIF()
SET(NATS_LIBRARY "${NATS_ROOT}/lib_x64/nats.lib")
SET(PROTOBUF_LIBRARY "${PROTOBUF_ROOT}/lib_x64/libprotobufd.lib")
ELSE(CMAKE_CL_64)
SET(ZLIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/zlib_x86")
SET(MYSQL_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/mysql_x86")
SET(LUA_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/luaj_x86")
SET(SODIUM_INCLUDE_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/include")
SET(OPENSSL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/openssl_x86")
SET(NATS_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/nats_x86")
SET(PROTOBUF_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/protobuf_x86")
IF(MSVC_VERSION GREATER 1800)
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v140/dynamic")
ELSEIF(MSVC_VERSION EQUAL 1800)
@ -80,6 +102,8 @@ IF(MSVC)
ELSE()
SET(SODIUM_LIBRARY_HINTS "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/libsodium/Win32/Release/v110/dynamic")
ENDIF()
SET(NATS_LIBRARY "${NATS_ROOT}/lib_x86/nats.lib")
SET(PROTOBUF_LIBRARY "${PROTOBUF_ROOT}/lib_x86/libprotobufd.lib")
ENDIF(CMAKE_CL_64)
#disable CRT warnings on windows cause they're annoying as shit and we use C functions everywhere
@ -131,6 +155,10 @@ IF(MSVC)
ADD_DEFINITIONS(-DNOMINMAX)
ELSE(MSVC)
SET(NATS_LIBRARY "${NATS_ROOT}/lib_x64/libnats.so")
SET(PROTOBUF_LIBRARY "${PROTOBUF_ROOT}/lib_x64/libprotobuf.so")
#Normally set by perl but we don't use the perl flags anymore so we set it.
ADD_DEFINITIONS(-DHAS_UNION_SEMUN)
ENDIF(MSVC)
@ -309,7 +337,7 @@ IF(EQEMU_BUILD_PERL)
INCLUDE_DIRECTORIES(SYSTEM "${PERL_INCLUDE_PATH}")
ENDIF(EQEMU_BUILD_PERL)
SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt)
SET(SERVER_LIBS common debug ${MySQL_LIBRARY_DEBUG} optimized ${MySQL_LIBRARY_RELEASE} ${ZLIB_LIBRARY} libuv fmt ${NATS_LIBRARY} ${PROTOBUF_LIBRARY})
FIND_PACKAGE(Sodium REQUIRED)
IF(SODIUM_FOUND)
@ -352,6 +380,8 @@ ENDIF(EQEMU_BUILD_LUA)
INCLUDE_DIRECTORIES(SYSTEM "${ZLIB_INCLUDE_DIRS}")
INCLUDE_DIRECTORIES(SYSTEM "${MySQL_INCLUDE_DIR}")
INCLUDE_DIRECTORIES(SYSTEM "${NATS_INCLUDE_DIR}")
INCLUDE_DIRECTORIES(SYSTEM "${PROTOBUF_INCLUDE_DIR}")
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/common/glm")
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/cereal")
INCLUDE_DIRECTORIES(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/libs/libuv/include" )

View File

@ -98,6 +98,7 @@ SET(common_sources
patches/titanium_limits.cpp
patches/uf.cpp
patches/uf_limits.cpp
proto/message.pb.cc
StackWalker/StackWalker.cpp
tinyxml/tinystr.cpp
tinyxml/tinyxml.cpp
@ -254,6 +255,7 @@ SET(common_headers
patches/uf_limits.h
patches/uf_ops.h
patches/uf_structs.h
proto/message.pb.h
StackWalker/StackWalker.h
tinyxml/tinystr.h
tinyxml/tinyxml.h

View File

@ -81,6 +81,10 @@ class EQEmuConfig
std::string QSDatabaseDB;
uint16 QSDatabasePort;
// From <nats/>
std::string NATSHost;
uint16 NATSPort;
// From <files/>
std::string SpellsFile;
std::string OpCodesFile;

View File

@ -104,6 +104,7 @@ void EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::MySQLError].log_to_console = Logs::General;
log_settings[Logs::Login_Server].log_to_console = Logs::General;
log_settings[Logs::Headless_Client].log_to_console = Logs::General;
log_settings[Logs::NATS].log_to_console = Logs::General;
/* Set Category enabled status on defaults */
log_settings[Logs::World_Server].is_category_enabled = 1;
@ -113,6 +114,7 @@ void EQEmuLogSys::LoadLogSettingsDefaults()
log_settings[Logs::Crash].is_category_enabled = 1;
log_settings[Logs::MySQLError].is_category_enabled = 1;
log_settings[Logs::Login_Server].is_category_enabled = 1;
log_settings[Logs::NATS].is_category_enabled = 1;
/* Declare process file names for log writing
If there is no process_file_name declared, no log file will be written, simply

View File

@ -90,6 +90,7 @@ enum LogCategory {
FixZ,
Food,
Traps,
NATS,
MaxCategoryID /* Don't Remove this*/
};
@ -144,7 +145,8 @@ static const char* LogCategoryName[LogCategory::MaxCategoryID] = {
"HP Update",
"FixZ",
"Food",
"Traps"
"Traps",
"NATS"
};
}

15056
common/proto/message.pb.cc Normal file

File diff suppressed because it is too large Load Diff

9458
common/proto/message.pb.h Normal file

File diff suppressed because it is too large Load Diff

8
protobuf/README.md Normal file
View File

@ -0,0 +1,8 @@
# Protobuf
* [https://developers.google.com/protocol-buffers/](Learn more about protobuf)
* Version is 3.5.1 (latest). In order to modify *.pb.cpp files, you need to have the [https://github.com/google/protobuf/releases](protoc binary).
* If you add any new .proto files, you need to include them into the CMakeList.txt entry of the respective dir, likely common/CMakeList.txt.
* By default, the generated cpp files are placed in the common/proto/* directory, while this is not best practice to have them versioned as they are auto generated files, it simplifies compiling source by not requiring protoc. (Perhaps later, we can look into adding this flow into cmake)
* Run build.bat or build.sh to build protobuf for different platforms.
* Look at each language subdirectory to learn more about building them

7
protobuf/build.bat Normal file
View File

@ -0,0 +1,7 @@
@echo off
del /q ..\common\proto\*
del /q go\eqproto\*
del /q python\proto\*pb2*
del /q java\eqproto\*.java
del /q csharp\proto\*.cs
protoc --cpp_out=../common/proto --go_out=go/eqproto --python_out=python/proto --csharp_out=csharp/proto --java_out=java message.proto

5
protobuf/build.sh Normal file
View File

@ -0,0 +1,5 @@
#!/bin/bash
set -e
echo "Cleaning up existing .pb* files"
rm -rf ../common/proto/* go/eqproto/* csharp/proto/*.cs java/eqproto/*.java python/proto/*pb2*
protoc --cpp_out=../common/proto --go_out=go/eqproto --python_out=python/proto --csharp_out=csharp/proto --java_out=java message.proto

883
protobuf/message.proto Normal file
View File

@ -0,0 +1,883 @@
syntax = "proto3";
package eqproto;
message ChannelMessage {
int32 chan_num = 1;
int32 language = 2;
string from = 3;
string to = 4;
string message = 5;
int32 guilddbid = 6;
string deliverto = 7;
int32 type = 8;
int32 minstatus = 9;
int32 fromadmin = 10;
bool noreply = 11;
bool is_emote = 12;
//0 not queued, 1 queued, 2 queue full, 3 offline
int32 queued = 13;
//You can specify a zone id if you want a message exclusively to one zone
int32 zone_id = 14;
}
message CommandMessage {
string author = 1;
string command = 2;
repeated string params = 3;
string result = 4;
bytes payload = 5;
}
//Daily Gain is a special system for tracking players progression in a daily snapshot.
message DailyGain {
int32 account_id = 1;
int32 character_id = 2;
int32 levels_gained = 3;
int32 experience_gained = 4;
int32 money_earned = 5;
string identity = 6;
}
//Entity is full of entity data.
message Entity {
int32 id = 1;
string name = 2;
int32 type = 3;
int32 hp = 4;
int32 level = 5;
Position position = 6;
int32 race = 7;
int32 class = 8;
}
message Entities {
repeated Entity entities = 1;
}
message Position {
float x = 1;
float y = 2;
float z = 3;
float h = 4;
}
message TextureProfile {
Texture Head = 1;
Texture Chest = 2;
Texture Arms = 3;
Texture Wrist = 4;
Texture Hands = 5;
Texture Legs = 6;
Texture Feet = 7;
Texture Primary = 8;
Texture Secondary = 9;
}
message Texture {
uint32 material = 1;
uint32 unknown1 = 2;
uint32 EliteModel = 3;
uint32 HerosForgeModel = 4;
uint32 Unknown2 = 5;
}
message TintProfile {
Tint Head = 1;
Tint Chest = 2;
Tint Arms = 3;
Tint Wrist = 4;
Tint Hands = 5;
Tint Legs = 6;
Tint Feet = 7;
Tint Primary = 8;
Tint Secondary = 9;
}
message Tint {
uint32 Blue = 1;
uint32 Green = 2;
uint32 Red = 3;
uint32 UseTint = 4; // if there's a tint, this is FF
uint32 Color = 5;
}
message Event {
OpCode op = 1;
bytes payload = 2;
}
//OP_Death
message DeathEvent {
uint32 spawn_id = 1;
uint32 killer_id = 2;
uint32 corpse_id = 3;
uint32 bind_zone_id = 4;
uint32 spell_id = 5;
uint32 attack_skill_id = 6;
uint32 damage = 7;
uint32 unknown028 = 8;
}
//OP_Damage
message DamageEvent {
uint32 target = 1;
uint32 source = 2;
uint32 type = 3; //slashing, etc. 231 (0xE7) for spells
uint32 spellid = 4;
uint32 damage = 5;
float force = 6;
float meleepush_xy = 7; // see above notes in Action_Struct
float meleepush_z = 8;
}
//OP_Assist OP_Camp
message EntityEvent {
uint32 entity_id = 1; //source of event trigger.
uint32 target_id = 2; //target or other/source/target entity
}
//OP_ChannelMessage
message ChannelMessageEvent {
string target_name = 1; // Tell recipient
string sender = 2; // The senders name (len might be wrong)
uint32 language = 3; // Language
uint32 chan_num = 4; // Channel
uint32 cm_unknown4 = 5; // ***Placeholder
uint32 skill_in_language = 6; // The players skill in this language? might be wrong
string message = 7; // Variable length message
}
//OP_WearChange
message WearChangeEvent {
uint32 spawn_id = 1;
uint32 material = 2;
uint32 unknown06 = 3;
uint32 elite_material = 4; // 1 for Drakkin Elite Material
uint32 hero_forge_model = 5; // New to VoA
uint32 unknown18 = 6; // New to RoF
Tint color = 7;
uint32 wear_slot_id = 8;
}
//OP_DeleteSpawn
message DeleteSpawnEvent {
uint32 spawn_id = 1; // Spawn ID to delete
uint32 decay = 2; // 0 = vanish immediately, 1 = 'Decay' sparklies for corpses.
}
//OP_MobHealth, OP_HPUpdate
message HPEvent {
uint32 spawn_id = 1;
uint32 cur_hp = 2;
uint32 max_hp = 3;
}
//OP_ClientUpdate
message PlayerPositionUpdateEvent {
uint32 spawn_id = 1;
int32 delta_heading = 2; // change in heading
int32 x_pos = 3; // x coord
int32 padding0002 = 4; // ***Placeholder
int32 y_pos = 5; // y coord
int32 animation = 6; // animation
int32 padding0006 = 7; // ***Placeholder
int32 z_pos = 8; // z coord
int32 delta_y = 9; // change in y
int32 delta_x = 10; // change in x
int32 heading = 11; // heading
int32 padding0014 = 12; // ***Placeholder
int32 delta_z = 13; // change in z
int32 padding0018 = 14; // ***Placeholder
}
//OP_Animation
message AnimationEvent {
uint32 spawnid = 1;
uint32 speed = 2;
uint32 action = 3;
}
//OP_ZoneEntry OP_NewSpawn
message SpawnEvent {
uint32 unknown0000= 1;
uint32 gm = 2; // 0=no, 1=gm
uint32 unknown0003 = 3;
uint32 aaitle = 4; // 0=none, 1=general, 2=archtype, 3=class
uint32 unknown0004 = 5;
uint32 anon = 6; // 0=normal, 1=anon, 2=roleplay
uint32 face = 7; // Face id for players
string name = 8; // Player's Name
uint32 deity = 9; // Player's Deity
uint32 unknown0073 = 10;
float size = 11; // Model size
uint32 unknown0079 = 12;
uint32 NPC = 13; // 0=player,1=npc,2=pc corpse,3=npc corpse,a
uint32 invis = 14; // Invis (0=not, 1=invis)
uint32 haircolor = 15; // Hair color
uint32 curHp = 16; // Current hp %%% wrong
uint32 max_hp = 17; // (name prolly wrong)takes on the value 100 for players, 100 or 110 for NPCs and 120 for PC corpses...
uint32 findable = 18; // 0=can't be found, 1=can be found
uint32 unknown0089 = 19;
int32 deltaHeading = 20; // change in heading
int32 x = 21; // x coord
int32 padding0054 = 22; // ***Placeholder
int32 y = 23; // y coord
int32 animation = 24; // animation
int32 padding0058 = 25; // ***Placeholder
int32 z = 26; // z coord
int32 deltaY = 27; // change in y
int32 deltaX = 28; // change in x
uint32 heading = 29; // heading
int32 padding0066 = 30; // ***Placeholder
int32 deltaZ = 31; // change in z
int32 padding0070 = 32; // ***Placeholder
uint32 eyecolor1 = 33; // Player's left eye color
uint32 unknown0115 = 34; // Was [24]
uint32 StandState = 35; // stand state for SoF+ 0x64 for normal animation
uint32 drakkin_heritage = 36; // Added for SoF
uint32 drakkin_tattoo = 37; // Added for SoF
uint32 drakkin_details = 38; // Added for SoF
uint32 showhelm = 39; // 0=no, 1=yes
uint32 unknown0140 = 40;
uint32 is_npc = 41; // 0=no, 1=yes
uint32 hairstyle = 42; // Hair style
uint32 beard = 43; // Beard style (not totally, sure but maybe!)
uint32 unknown0147 = 44;
uint32 level = 45; // Spawn Level
uint32 PlayerState = 46; // Controls animation stuff // None = 0, Open = 1, WeaponSheathed = 2, Aggressive = 4, ForcedAggressive = 8, InstrumentEquipped = 16, Stunned = 32, PrimaryWeaponEquipped = 64, SecondaryWeaponEquipped = 128
uint32 beardcolor = 47; // Beard color
string suffix = 48; // Player's suffix (of Veeshan, etc.)
uint32 petOwnerId = 49; // If this is a pet, the spawn id of owner
uint32 guildrank = 50; // 0=normal, 1=officer, 2=leader
uint32 unknown0194 = 51;
TextureProfile equipment = 52;
float runspeed = 53; // Speed when running
uint32 afk = 54; // 0=no, 1=afk
uint32 guildID = 55; // Current guild
string title = 56; // Title
uint32 unknown0274 = 57; // non-zero prefixes name with '!'
uint32 set_to_0xFF = 58; // ***Placeholder (all ff)
uint32 helm = 59; // Helm texture
uint32 race = 60; // Spawn race
uint32 unknown0288 = 61;
string lastName = 62; // Player's Lastname
float walkspeed = 63; // Speed when walking
uint32 unknown0328 = 64;
uint32 is_pet = 65; // 0=no, 1=yes
uint32 light = 66; // Spawn's lightsource %%% wrong
uint32 class_ = 67; // Player's class
uint32 eyecolor2 = 68; // Left eye color
uint32 flymode = 69;
uint32 gender = 70; // Gender (0=male, 1=female)
uint32 bodytype = 71; // Bodytype
uint32 unknown0336 = 72;
//union
uint32 equip_chest2 = 73; // Second place in packet for chest texture (usually 0xFF in live packets) // Not sure why there are 2 of them, but it effects chest texture!
uint32 mount_color = 74; // drogmor: 0=white, 1=black, 2=green, 3=red horse: 0=brown, 1=white, 2=black, 3=tan
//endunion
uint32 spawnId = 75; // Spawn Id
uint32 unknown0344 = 76;
uint32 IsMercenary = 77;
TintProfile equipment_tint = 78;
uint32 lfg = 79; // 0=off, 1=lfg on
bool DestructibleObject = 80; // Only used to flag as a destrible object
string DestructibleModel = 82; // Model of the Destructible Object - Required - Seen "DEST_TNT_G"
string DestructibleName2 = 83; // Secondary name - Not Required - Seen "a_tent"
string DestructibleString = 84; // Unknown - Not Required - Seen "ZoneActor_01186"
uint32 DestructibleAppearance = 85; // Damage Appearance
uint32 DestructibleUnk1 = 86;
uint32 DestructibleID1 = 87;
uint32 DestructibleID2 = 88;
uint32 DestructibleID3 = 89;
uint32 DestructibleID4 = 90;
uint32 DestructibleUnk2 = 91;
uint32 DestructibleUnk3 = 92;
uint32 DestructibleUnk4 = 93;
uint32 DestructibleUnk5 = 94;
uint32 DestructibleUnk6 = 95;
uint32 DestructibleUnk7 = 96;
uint32 DestructibleUnk8 = 97;
uint32 DestructibleUnk9 = 98;
bool targetable_with_hotkey = 99;
bool show_name= 100;
}
enum OpCode {
//option allow_alias = true;
OP_Unknown = 0;
OP_ExploreUnknown = 1;
OP_0x0193 = 2;
OP_0x0347 = 3;
OP_AAAction = 4;
OP_AAExpUpdate = 5;
OP_AcceptNewTask = 6;
OP_AckPacket = 7;
OP_Action = 8;
OP_Action2 = 9;
OP_AddNimbusEffect = 10;
OP_AdventureData = 11;
OP_AdventureDetails = 12;
OP_AdventureFinish = 13;
OP_AdventureInfo = 14;
OP_AdventureInfoRequest = 15;
OP_AdventureLeaderboardReply = 16;
OP_AdventureLeaderboardRequest = 17;
OP_AdventureMerchantPurchase = 18;
OP_AdventureMerchantRequest = 19;
OP_AdventureMerchantResponse = 20;
OP_AdventureMerchantSell = 21;
OP_AdventurePointsUpdate = 22;
OP_AdventureRequest = 23;
OP_AdventureStatsReply = 24;
OP_AdventureStatsRequest = 25;
OP_AdventureUpdate = 26;
OP_AggroMeterLockTarget = 27;
OP_AggroMeterTargetInfo = 28;
OP_AggroMeterUpdate = 29;
OP_AltCurrency = 30;
OP_AltCurrencyMerchantReply = 31;
OP_AltCurrencyMerchantRequest = 32;
OP_AltCurrencyPurchase = 33;
OP_AltCurrencyReclaim = 34;
OP_AltCurrencySell = 35;
OP_AltCurrencySellSelection = 36;
OP_Animation = 37; //supported
OP_AnnoyingZoneUnknown = 38;
OP_ApplyPoison = 39;
OP_ApproveName = 40;
OP_ApproveWorld = 41;
OP_ApproveZone = 42;
OP_Assist = 43; //supported
OP_AssistGroup = 44;
OP_AugmentInfo = 45;
OP_AugmentItem = 46;
OP_AutoAttack = 47;
OP_AutoAttack2 = 48;
OP_AutoFire = 49;
OP_Bandolier = 50;
OP_BankerChange = 51;
OP_Barter = 52;
OP_Bazaar = 53;
OP_BazaarInspect = 54;
OP_BazaarSearch = 55;
OP_BecomeCorpse = 56;
OP_BecomeTrader = 57;
OP_Begging = 58;
OP_BeginCast = 59;
OP_Bind_Wound = 60;
OP_BlockedBuffs = 61;
OP_BoardBoat = 62;
OP_Buff = 63;
OP_BuffCreate = 64;
OP_BuffRemoveRequest = 65;
OP_Bug = 66;
OP_CameraEffect = 67;
OP_Camp = 68; //supported
OP_CancelSneakHide = 69;
OP_CancelTask = 70;
OP_CancelTrade = 71;
OP_CastSpell = 72;
OP_ChangeSize = 73;
OP_ChannelMessage = 74;
OP_CharacterCreate = 75;
OP_CharacterCreateRequest = 76;
OP_CharInventory = 77;
OP_Charm = 78;
OP_ChatMessage = 79; //used by lua
OP_ClearAA = 80;
OP_ClearBlockedBuffs = 81;
OP_ClearLeadershipAbilities = 82;
OP_ClearNPCMarks = 83;
OP_ClearObject = 84;
OP_ClearSurname = 85;
OP_ClickDoor = 86;
OP_ClickObject = 87;
OP_ClickObjectAction = 88;
OP_ClientError = 89;
OP_ClientReady = 90;
OP_ClientTimeStamp = 91;
OP_ClientUpdate = 92; //supported
OP_CloseContainer = 93;
OP_CloseTributeMaster = 94;
OP_ColoredText = 95;
OP_CombatAbility = 96;
OP_Command = 97;
OP_CompletedTasks = 98;
OP_ConfirmDelete = 99;
OP_Consent = 100;
OP_ConsentDeny = 101;
OP_ConsentResponse = 102;
OP_Consider = 103;
OP_ConsiderCorpse = 104;
OP_Consume = 105;
OP_ControlBoat = 106;
OP_CorpseDrag = 107;
OP_CorpseDrop = 108;
OP_CrashDump = 109;
OP_CrystalCountUpdate = 110;
OP_CrystalCreate = 111;
OP_CrystalReclaim = 112;
OP_CustomTitles = 113;
OP_Damage = 114;
OP_Death = 115;
OP_DelegateAbility = 116;
OP_DeleteCharacter = 117;
OP_DeleteCharge = 118;
OP_DeleteItem = 119;
OP_DeletePetition = 120;
OP_DeleteSpawn = 121; //supported
OP_DeleteSpell = 122;
OP_DenyResponse = 123;
OP_Disarm = 124;
OP_DisarmTraps = 125;
OP_DisciplineTimer = 126;
OP_DisciplineUpdate = 127;
OP_DiscordMerchantInventory = 128;
OP_DoGroupLeadershipAbility = 129;
OP_DuelResponse = 130;
OP_DuelResponse2 = 131;
OP_DumpName = 132;
OP_Dye = 133;
OP_DynamicWall = 134;
OP_DzAddPlayer = 135;
OP_DzChooseZone = 136;
OP_DzCompass = 137;
OP_DzExpeditionEndsWarning = 138;
OP_DzExpeditionInfo = 139;
OP_DzExpeditionList = 140;
OP_DzJoinExpeditionConfirm = 141;
OP_DzJoinExpeditionReply = 142;
OP_DzLeaderStatus = 143;
OP_DzListTimers = 144;
OP_DzMakeLeader = 145;
OP_DzMemberList = 146;
OP_DzMemberStatus = 147;
OP_DzPlayerList = 148;
OP_DzQuit = 149;
OP_DzRemovePlayer = 150;
OP_DzSwapPlayer = 151;
OP_Emote = 152;
OP_EndLootRequest = 153;
OP_EnduranceUpdate = 154;
OP_EnterChat = 155;
OP_EnterWorld = 156;
OP_EnvDamage = 157;
OP_ExpansionInfo = 158;
OP_ExpUpdate = 159;
OP_FaceChange = 160;
OP_Feedback = 161;
OP_FeignDeath = 162;
OP_FellowshipUpdate = 163;
OP_FindPersonReply = 164;
OP_FindPersonRequest = 165;
OP_FinishTrade = 166;
OP_FinishWindow = 167;
OP_FinishWindow2 = 168;
OP_Fishing = 169;
OP_Fling = 170;
OP_FloatListThing = 171;
OP_Forage = 172;
OP_ForceFindPerson = 173;
OP_FormattedMessage = 174;
OP_FriendsWho = 175;
OP_GetGuildMOTD = 176;
OP_GetGuildMOTDReply = 177;
OP_GetGuildsList = 178;
OP_GiveMoney = 179;
OP_GMApproval = 180;
OP_GMBecomeNPC = 181;
OP_GMDelCorpse = 182;
OP_GMEmoteZone = 183;
OP_GMEndTraining = 184;
OP_GMEndTrainingResponse = 185;
OP_GMFind = 186;
OP_GMGoto = 187;
OP_GMHideMe = 188;
OP_GMKick = 189;
OP_GMKill = 190;
OP_GMLastName = 191;
OP_GMNameChange = 192;
OP_GMSearchCorpse = 193;
OP_GMServers = 194;
OP_GMSummon = 195;
OP_GMToggle = 196;
OP_GMTraining = 197;
OP_GMTrainSkill = 198;
OP_GMTrainSkillConfirm = 199;
OP_GMZoneRequest = 200;
OP_GMZoneRequest2 = 201;
OP_GroundSpawn = 202;
OP_GroupAcknowledge = 203;
OP_GroupCancelInvite = 204;
OP_GroupDelete = 205;
OP_GroupDisband = 206;
OP_GroupDisbandOther = 207;
OP_GroupDisbandYou = 208;
OP_GroupFollow = 209;
OP_GroupFollow2 = 210;
OP_GroupInvite = 211;
OP_GroupInvite2 = 212;
OP_GroupLeaderChange = 213;
OP_GroupLeadershipAAUpdate = 214;
OP_GroupMakeLeader = 215;
OP_GroupMentor = 216;
OP_GroupRoles = 217;
OP_GroupUpdate = 218;
OP_GroupUpdateB = 219;
OP_GroupUpdateLeaderAA = 220;
OP_GuildBank = 221;
OP_GuildBankItemList = 222;
OP_GuildCreate = 223;
OP_GuildDelete = 224;
OP_GuildDemote = 225;
OP_GuildInvite = 226;
OP_GuildInviteAccept = 227;
OP_GuildLeader = 228;
OP_GuildManageAdd = 229;
OP_GuildManageBanker = 230;
OP_GuildManageRemove = 231;
OP_GuildManageStatus = 232;
OP_GuildMemberLevelUpdate = 233;
OP_GuildMemberList = 234;
OP_GuildMemberUpdate = 235;
OP_GuildMOTD = 236;
OP_GuildPeace = 237;
OP_GuildPromote = 238;
OP_GuildPublicNote = 239;
OP_GuildRemove = 240;
OP_GuildsList = 241;
OP_GuildStatus = 242;
OP_GuildTributeInfo = 243;
OP_GuildUpdateURLAndChannel = 244;
OP_GuildWar = 245;
OP_Heartbeat = 246;
OP_Hide = 247;
OP_HideCorpse = 248;
OP_HPUpdate = 249; //supported
OP_Illusion = 250;
OP_IncreaseStats = 251;
OP_InitialHPUpdate = 252;
OP_InitialMobHealth = 253;
OP_InspectAnswer = 254;
OP_InspectBuffs = 255;
OP_InspectMessageUpdate = 256;
OP_InspectRequest = 257;
OP_InstillDoubt = 258;
OP_InterruptCast = 259;
OP_ItemLinkClick = 260;
OP_ItemLinkResponse = 261;
OP_ItemLinkText = 262;
OP_ItemName = 263;
OP_ItemPacket = 264;
OP_ItemPreview = 265;
OP_ItemRecastDelay = 266;
OP_ItemVerifyReply = 267;
OP_ItemVerifyRequest = 268;
OP_ItemViewUnknown = 269;
OP_Jump = 270;
OP_KeyRing = 271;
OP_KnowledgeBase = 272;
OP_LDoNButton = 273;
OP_LDoNDisarmTraps = 274;
OP_LDoNInspect = 275;
OP_LDoNOpen = 276;
OP_LDoNPickLock = 277;
OP_LDoNSenseTraps = 278;
OP_LeadershipExpToggle = 279;
OP_LeadershipExpUpdate = 280;
OP_LeaveAdventure = 281;
OP_LeaveBoat = 282;
OP_LevelAppearance = 283;
OP_LevelUpdate = 284;
OP_LFGAppearance = 285;
OP_LFGCommand = 286;
OP_LFGGetMatchesRequest = 287;
OP_LFGGetMatchesResponse = 288;
OP_LFGResponse = 289;
OP_LFGuild = 290;
OP_LFPCommand = 291;
OP_LFPGetMatchesRequest = 292;
OP_LFPGetMatchesResponse = 293;
OP_LinkedReuse = 294;
OP_LoadSpellSet = 295;
OP_LocInfo = 296;
OP_LockoutTimerInfo = 297;
OP_Login = 298;
OP_LoginAccepted = 299;
OP_LoginComplete = 300;
OP_LoginUnknown1 = 301;
OP_LoginUnknown2 = 302;
OP_Logout = 303;
OP_LogoutReply = 304;
OP_LogServer = 305;
OP_LootComplete = 306;
OP_LootItem = 307;
OP_LootRequest = 308;
OP_ManaChange = 309;
OP_ManaUpdate = 310;
OP_MarkNPC = 311;
OP_Marquee = 312;
OP_MemorizeSpell = 313;
OP_Mend = 314;
OP_MendHPUpdate = 315;
OP_MercenaryAssign = 316;
OP_MercenaryCommand = 317;
OP_MercenaryDataRequest = 318;
OP_MercenaryDataResponse = 319;
OP_MercenaryDataUpdate = 320;
OP_MercenaryDataUpdateRequest = 321;
OP_MercenaryDismiss = 322;
OP_MercenaryHire = 323;
OP_MercenarySuspendRequest = 324;
OP_MercenarySuspendResponse = 325;
OP_MercenaryTimer = 326;
OP_MercenaryTimerRequest = 327;
OP_MercenaryUnknown1 = 328;
OP_MercenaryUnsuspendResponse = 329;
OP_MobEnduranceUpdate = 330;
OP_MobHealth = 331; //supported
OP_MobManaUpdate = 332;
OP_MobRename = 333;
OP_MobUpdate = 334; // not used anymore, here for lecacy reasons eqextractor
OP_MoneyOnCorpse = 335;
OP_MoneyUpdate = 336;
OP_MOTD = 337;
OP_MoveCoin = 338;
OP_MoveDoor = 339;
OP_MoveItem = 340;
OP_MoveLogDisregard = 341;
OP_MoveLogRequest = 342;
OP_MultiLineMsg = 343;
OP_NewSpawn = 344; //supported
OP_NewTitlesAvailable = 345;
OP_NewZone = 346;
OP_OnLevelMessage = 347;
OP_OpenContainer = 348;
OP_OpenDiscordMerchant = 349;
OP_OpenGuildTributeMaster = 350;
OP_OpenInventory = 351;
OP_OpenNewTasksWindow = 352;
OP_OpenTributeMaster = 353;
OP_PDeletePetition = 354;
OP_PetBuffWindow = 355;
OP_PetCommands = 356;
OP_PetCommandState = 357;
OP_PetHoTT = 358;
OP_Petition = 359;
OP_PetitionBug = 360;
OP_PetitionCheckIn = 361;
OP_PetitionCheckout = 362;
OP_PetitionCheckout2 = 363;
OP_PetitionDelete = 364;
OP_PetitionQue = 365;
OP_PetitionRefresh = 366;
OP_PetitionResolve = 367;
OP_PetitionSearch = 368;
OP_PetitionSearchResults = 369;
OP_PetitionSearchText = 370;
OP_PetitionUnCheckout = 371;
OP_PetitionUpdate = 372;
OP_PickPocket = 373;
OP_PlayerProfile = 374;
OP_PlayerStateAdd = 375;
OP_PlayerStateRemove = 376;
OP_PlayEverquestRequest = 377;
OP_PlayEverquestResponse = 378;
OP_PlayMP3 = 379;
OP_Poll = 380;
OP_PollResponse = 381;
OP_PopupResponse = 382;
OP_PostEnterWorld = 383; //this is really OP_WorldAccessGrant
OP_PotionBelt = 384;
OP_PreLogoutReply = 385;
OP_PurchaseLeadershipAA = 386;
OP_PVPLeaderBoardDetailsReply = 387;
OP_PVPLeaderBoardDetailsRequest = 388;
OP_PVPLeaderBoardReply = 389;
OP_PVPLeaderBoardRequest = 390;
OP_PVPStats = 391;
OP_QueryResponseThing = 392;
OP_RaidInvite = 393;
OP_RaidJoin = 394;
OP_RaidUpdate = 395;
OP_RandomNameGenerator = 396;
OP_RandomReply = 397;
OP_RandomReq = 398;
OP_ReadBook = 399;
OP_RecipeAutoCombine = 400;
OP_RecipeDetails = 401;
OP_RecipeReply = 402;
OP_RecipesFavorite = 403;
OP_RecipesSearch = 404;
OP_ReclaimCrystals = 405;
OP_ReloadUI = 406;
OP_RemoveAllDoors = 407;
OP_RemoveBlockedBuffs = 408;
OP_RemoveNimbusEffect = 409;
OP_RemoveTrap = 410;
OP_Report = 411;
OP_ReqClientSpawn = 412;
OP_ReqNewZone = 413;
OP_RequestClientZoneChange = 414;
OP_RequestDuel = 415;
OP_RequestKnowledgeBase = 416;
OP_RequestTitles = 417;
OP_RespawnWindow = 418;
OP_RespondAA = 419;
OP_RestState = 420;
OP_Rewind = 421;
OP_RezzAnswer = 422;
OP_RezzComplete = 423;
OP_RezzRequest = 424;
OP_Sacrifice = 425;
OP_SafeFallSuccess = 426;
OP_SafePoint = 427;
OP_Save = 428;
OP_SaveOnZoneReq = 429;
OP_SelectTribute = 430;
OP_SendAAStats = 431;
OP_SendAATable = 432;
OP_SendCharInfo = 433;
OP_SendExpZonein = 434;
OP_SendFindableNPCs = 435;
OP_SendGuildTributes = 436;
OP_SendLoginInfo = 437;
OP_SendMaxCharacters = 438;
OP_SendMembership = 439;
OP_SendMembershipDetails = 440;
OP_SendSystemStats = 441;
OP_SendTitleList = 442;
OP_SendTributes = 443;
OP_SendZonepoints = 444;
OP_SenseHeading = 445;
OP_SenseTraps = 446;
OP_ServerListRequest = 447;
OP_ServerListResponse = 448;
OP_SessionReady = 449;
OP_SetChatServer = 450;
OP_SetChatServer2 = 451;
OP_SetGroupTarget = 452;
OP_SetGuildMOTD = 453;
OP_SetGuildRank = 454;
OP_SetRunMode = 455;
OP_SetServerFilter = 456;
OP_SetStartCity = 457;
OP_SetTitle = 458;
OP_SetTitleReply = 459;
OP_Shielding = 460;
OP_ShopDelItem = 461;
OP_ShopEnd = 462;
OP_ShopEndConfirm = 463;
OP_ShopItem = 464;
OP_ShopPlayerBuy = 465;
OP_ShopPlayerSell = 466;
OP_ShopRequest = 467;
OP_SimpleMessage = 468;
OP_SkillUpdate = 469;
OP_Sneak = 470;
OP_Some3ByteHPUpdate = 471;
OP_Some6ByteHPUpdate = 472;
OP_SomeItemPacketMaybe = 473;
OP_Sound = 474;
OP_SpawnAppearance = 475;
OP_SpawnDoor = 476;
OP_SpawnPositionUpdate = 477;
OP_SpecialMesg = 478;
OP_SpellEffect = 479;
OP_Split = 480;
OP_Stamina = 481;
OP_Stun = 482;
OP_Surname = 483;
OP_SwapSpell = 484;
OP_TargetBuffs = 485;
OP_TargetCommand = 486;
OP_TargetHoTT = 487;
OP_TargetMouse = 488;
OP_TargetReject = 489;
OP_TaskActivity = 490;
OP_TaskActivityComplete = 491;
OP_TaskDescription = 492;
OP_TaskHistoryReply = 493;
OP_TaskHistoryRequest = 494;
OP_TaskMemberList = 495;
OP_Taunt = 496;
OP_TestBuff = 497;
OP_TGB = 498;
OP_TimeOfDay = 499;
OP_Track = 500;
OP_TrackTarget = 501;
OP_TrackUnknown = 502;
OP_TradeAcceptClick = 503;
OP_TradeBusy = 504;
OP_TradeCoins = 505;
OP_TradeMoneyUpdate = 506;
OP_Trader = 507;
OP_TraderBuy = 508;
OP_TraderDelItem = 509;
OP_TradeRequest = 510;
OP_TradeRequestAck = 511;
OP_TraderItemUpdate = 512;
OP_TraderShop = 513;
OP_TradeSkillCombine = 514;
OP_Translocate = 515;
OP_TributeInfo = 516;
OP_TributeItem = 517;
OP_TributeMoney = 518;
OP_TributeNPC = 519;
OP_TributePointUpdate = 520;
OP_TributeTimer = 521;
OP_TributeToggle = 522;
OP_TributeUpdate = 523;
OP_Untargetable = 524;
OP_UpdateAA = 525;
OP_UpdateAura = 526;
OP_UpdateLeadershipAA = 527;
OP_VetClaimReply = 528;
OP_VetClaimRequest = 529;
OP_VetRewardsAvaliable = 530;
OP_VoiceMacroIn = 531;
OP_VoiceMacroOut = 532;
OP_WeaponEquip1 = 533;
OP_WearChange = 534; //supported
OP_Weather = 535;
OP_Weblink = 536;
OP_WhoAllRequest = 537;
OP_WhoAllResponse = 538;
OP_World_Client_CRC1 = 539;
OP_World_Client_CRC2 = 540;
OP_WorldClientReady = 541;
OP_WorldComplete = 542;
OP_WorldLogout = 543;
OP_WorldObjectsSent = 544;
OP_WorldUnknown001 = 545;
OP_XTargetAutoAddHaters = 546;
OP_XTargetOpen = 547;
OP_XTargetOpenResponse = 548;
OP_XTargetRequest = 549;
OP_XTargetResponse = 550;
OP_YellForHelp = 551;
OP_ZoneChange = 552;
OP_ZoneComplete = 553;
OP_ZoneEntry = 554; //supported
OP_ZoneGuildList = 555;
OP_ZoneInUnknown = 556;
OP_ZonePlayerToBind = 557;
OP_ZoneServerInfo = 558;
OP_ZoneServerReady = 559;
OP_ZoneSpawns = 560;
OP_ZoneUnavail = 561;
OP_ResetAA = 562;
OP_Buddy = 563;
OP_ChannelAnnounceJoin = 564;
OP_ChannelAnnounceLeave = 565;
OP_Ignore = 566;
OP_Mail = 567;
OP_MailboxChange = 568;
OP_MailDeliveryStatus = 569;
OP_MailHeader = 570;
OP_MailHeaderCount = 571;
OP_MailLogin = 572;
OP_MailNew = 573;
OP_MailSendBody = 574;
}

View File

@ -13,6 +13,7 @@ SET(world_sources
lfplist.cpp
login_server.cpp
login_server_list.cpp
nats_manager.cpp
net.cpp
queryserv.cpp
ucs.cpp
@ -40,6 +41,7 @@ SET(world_headers
lfplist.h
login_server.h
login_server_list.h
nats_manager.h
net.h
queryserv.h
sof_char_create_data.h

View File

@ -46,6 +46,7 @@
#include "clientlist.h"
#include "wguild_mgr.h"
#include "sof_char_create_data.h"
#include "nats_manager.h"
#include <iostream>
#include <iomanip>
@ -84,6 +85,7 @@ extern ClientList client_list;
extern EQEmu::Random emu_random;
extern uint32 numclients;
extern volatile bool RunLoops;
extern NatsManager nats;
Client::Client(EQStreamInterface* ieqs)
: autobootup_timeout(RuleI(World, ZoneAutobootTimeoutMS)),
@ -799,6 +801,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
}
else {
Log(Logs::Detail, Logs::World_Server, "'%s' is trying to go home before they're able...", char_name);
nats.SendAdminMessage(StringFormat("Hacker: %s [%s]: MQGoHome: player tried to go home before they were able.", GetAccountName(), char_name));
database.SetHackerFlag(GetAccountName(), char_name, "MQGoHome: player tried to go home before they were able.");
eqs->Close();
return true;
@ -823,6 +826,7 @@ bool Client::HandleEnterWorldPacket(const EQApplicationPacket *app) {
}
else {
Log(Logs::Detail, Logs::World_Server, "'%s' is trying to go to tutorial but are not allowed...", char_name);
nats.SendAdminMessage(StringFormat("Hacker %s [%s]: MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.", GetAccountName(), char_name));
database.SetHackerFlag(GetAccountName(), char_name, "MQTutorial: player tried to enter the tutorial without having tutorial enabled for this character.");
eqs->Close();
return true;

View File

@ -1467,4 +1467,59 @@ void ClientList::OnTick(EQ::Timer *t)
}
web_interface.SendEvent(out);
}
std::string ClientList::GetWhoAll() {
std::string reply = "";
LinkedListIterator<ClientListEntry*> iterator(clientlist);
ClientListEntry* cle = 0;
uint32 x = 0;
char* output = 0;
uint32 outsize = 0, outlen = 0;
reply.append("Players on server:\n");
iterator.Reset();
while (iterator.MoreElements()) {
cle = iterator.GetData();
const char* tmpZone = database.GetZoneName(cle->zone());
if (cle->Online() < CLE_Status_Zoning ||
x > 20) {
iterator.Advance();
continue;
}
if (cle->Admin() >= 250) reply.append("* GM-Impossible * ");
else if (cle->Admin() >= 200) reply.append("* GM-Mgmt * ");
else if (cle->Admin() >= 180) reply.append("* GM-Coder * ");
else if (cle->Admin() >= 170) reply.append("* GM-Areas * ");
else if (cle->Admin() >= 160) reply.append("* QuestMaster * ");
else if (cle->Admin() >= 150) reply.append("* GM-Lead Admin * ");
else if (cle->Admin() >= 100) reply.append("* GM-Admin * ");
else if (cle->Admin() >= 95) reply.append("* GM-Staff * ");
else if (cle->Admin() >= 90) reply.append("* EQ Support * ");
else if (cle->Admin() >= 85) reply.append("* GM-Tester * ");
else if (cle->Admin() >= 81) reply.append("* Senior Guide * ");
else if (cle->Admin() >= 80) reply.append("* QuestTroupe * ");
else if (cle->Admin() >= 50) reply.append("* Guide * ");
//else if (cle->Admin() >= 20) reply.append("* Apprentice Guide * ");
//else if (cle->Admin() >= 10) reply.append("* Steward * ");
if (cle->Anon() == 2) reply.append("[RolePlay");
else if (cle->Anon() == 1) reply.append("[ANON");
else reply.append("[");
reply.append(StringFormat(" %i %s ] %s", cle->level(), GetClassIDName(cle->class_(), cle->level()), cle->name()));
reply.append(StringFormat(" %s zone: %s", GetRaceIDName(cle->race()), database.GetZoneName(cle->zone())));
if (guild_mgr.GuildExists(cle->GuildID())) reply.append(StringFormat(" <%s>", guild_mgr.GetGuildName(cle->GuildID())));
if (cle->LFG()) reply.append(" LFG");
reply.append("\n");
x++;
iterator.Advance();
}
if (x >= 20) reply.append("First 20 shown, ");
reply.append(StringFormat("%u total players online.", x));
return reply;
}

View File

@ -69,6 +69,7 @@ public:
int GetClientCount();
void GetClients(const char *zone_name, std::vector<ClientListEntry *> &into);
std::string GetWhoAll();
private:
void OnTick(EQ::Timer *t);
inline uint32 GetNextCLEID() { return NextCLEID++; }

268
world/nats_manager.cpp Normal file
View File

@ -0,0 +1,268 @@
#include "nats_manager.h"
#include "nats.h"
#include "zonelist.h"
#include "login_server_list.h"
#include "clientlist.h"
#include "worlddb.h"
#include "../common/seperator.h"
#include "../common/eqemu_logsys.h"
#ifndef PROTO_H
#define PROTO_H
#include "../common/proto/message.pb.h"
#endif
#include "../common/servertalk.h"
#include "../common/string_util.h"
extern ZSList zoneserver_list;
extern LoginServerList loginserverlist;
extern ClientList client_list;
const WorldConfig *worldConfig;
NatsManager::NatsManager()
{
//new timers, object initialization
worldConfig = WorldConfig::get();
}
NatsManager::~NatsManager()
{
// Destroy all our objects to avoid report of memory leak
natsStatistics_Destroy(stats);
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
// To silence reports of memory still in used with valgrind
nats_Close();
}
bool NatsManager::connect() {
auto ncs = natsConnection_Status(conn);
if (ncs == CONNECTED) return true;
if (nats_timer.Enabled() && !nats_timer.Check()) return false;
natsOptions *opts = NULL;
natsOptions_Create(&opts);
natsOptions_SetMaxReconnect(opts, 0);
natsOptions_SetReconnectWait(opts, 0);
natsOptions_SetAllowReconnect(opts, false);
//The timeout is going to cause a 100ms delay on all connected clients every X seconds (20s)
//since this blocks the connection. It can be set lower or higher delay,
//but since NATS is a second priority I wanted server impact minimum.
natsOptions_SetTimeout(opts, 100);
std::string connection = StringFormat("nats://%s:%d", worldConfig->NATSHost.c_str(), worldConfig->NATSPort);
if (worldConfig->NATSHost.length() == 0) connection = "nats://localhost:4222";
natsOptions_SetURL(opts, connection.c_str());
s = natsConnection_Connect(&conn, opts);
natsOptions_Destroy(opts);
if (s != NATS_OK) {
Log(Logs::General, Logs::NATS, "failed to connect to %s: %s, retrying in 20s", connection.c_str(), nats_GetLastError(&s));
conn = NULL;
nats_timer.Enable();
nats_timer.SetTimer(20000);
return false;
}
Log(Logs::General, Logs::NATS, "connected to %s", connection.c_str());
nats_timer.Disable();
return true;
}
void NatsManager::Process()
{
natsMsg *msg = NULL;
if (!connect()) return;
s = NATS_OK;
for (int count = 0; (s == NATS_OK) && count < 5; count++)
{
s = natsSubscription_NextMsg(&msg, channelMessageSub, 1);
if (s != NATS_OK) break;
Log(Logs::General, Logs::NATS, "Got Broadcast Message '%s'", natsMsg_GetData(msg));
eqproto::ChannelMessage message;
if (!message.ParseFromString(natsMsg_GetData(msg))) {
Log(Logs::General, Logs::NATS, "Failed to marshal");
natsMsg_Destroy(msg);
continue;
}
ChannelMessageEvent(&message);
}
s = NATS_OK;
for (int count = 0; (s == NATS_OK) && count < 5; count++)
{
s = natsSubscription_NextMsg(&msg, commandMessageSub, 1);
if (s != NATS_OK) break;
Log(Logs::General, Logs::NATS, "Got Command Message '%s'", natsMsg_GetData(msg));
eqproto::CommandMessage message;
if (!message.ParseFromString(natsMsg_GetData(msg))) {
Log(Logs::General, Logs::NATS, "Failed to marshal");
natsMsg_Destroy(msg);
continue;
}
CommandMessageEvent(&message, natsMsg_GetReply(msg));
}
}
void NatsManager::OnChannelMessage(ServerChannelMessage_Struct* msg) {
if (!connect()) return;
eqproto::ChannelMessage message;
message.set_fromadmin(msg->fromadmin);
message.set_deliverto(msg->deliverto);
message.set_guilddbid(msg->guilddbid);
message.set_noreply(msg->noreply);
message.set_queued(msg->queued);
message.set_chan_num(msg->chan_num);
message.set_message(msg->message);
message.set_to(msg->to);
message.set_language(msg->language);
message.set_from(msg->from);
SendChannelMessage(&message);
return;
}
void NatsManager::OnEmoteMessage(ServerEmoteMessage_Struct* msg) {
if (!connect()) return;
eqproto::ChannelMessage message;
message.set_guilddbid(msg->guilddbid);
message.set_minstatus(msg->minstatus);
message.set_type(msg->type);
message.set_message(msg->message);
message.set_to(msg->to);
message.set_is_emote(true);
SendChannelMessage(&message);
return;
}
void NatsManager::SendAdminMessage(std::string adminMessage) {
if (!connect()) return;
eqproto::ChannelMessage message;
message.set_message(adminMessage.c_str());
std::string pubMessage;
if (!message.SerializeToString(&pubMessage)) {
Log(Logs::General, Logs::NATS, "Failed to serialize message to string");
return;
}
s = natsConnection_PublishString(conn, "AdminMessage", pubMessage.c_str());
if (s != NATS_OK) {
Log(Logs::General, Logs::NATS, "Failed to SendAdminMessage");
}
Log(Logs::General, Logs::NATS, "AdminMessage: %s", adminMessage.c_str());
}
//Send (publish) message to NATS
void NatsManager::SendChannelMessage(eqproto::ChannelMessage* message) {
if (!connect()) return;
std::string pubMessage;
if (!message->SerializeToString(&pubMessage)) {
Log(Logs::General, Logs::NATS, "Failed to serialize message to string");
return;
}
s = natsConnection_PublishString(conn, "ChannelMessage", pubMessage.c_str());
if (s != NATS_OK) {
Log(Logs::General, Logs::NATS, "Failed to send ChannelMessageEvent");
}
}
void NatsManager::CommandMessageEvent(eqproto::CommandMessage* message, const char* reply) {
if (!connect()) return;
std::string pubMessage;
//Log(Logs::General, Logs::NATS, "Command: %s", message->command().c_str());
// message->params()
if (message->command().compare("who") == 0) {
message->set_result(client_list.GetWhoAll());
}
if (message->command().compare("unlock") == 0) {
WorldConfig::UnlockWorld();
if (loginserverlist.Connected()) loginserverlist.SendStatus();
message->set_result("Server is now unlocked.");
}
if (message->command().compare("lock") == 0) {
WorldConfig::LockWorld();
if (loginserverlist.Connected()) loginserverlist.SendStatus();
message->set_result("Server is now locked.");
}
if(message->command().compare("worldshutdown") == 0) {
uint32 time=0;
uint32 interval=0;
if(message->params_size() < 1) {
message->set_result("worldshutdown - Shuts down the server and all zones.\n \
Usage: worldshutdown now - Shuts down the server and all zones immediately.\n \
Usage: worldshutdown disable - Stops the server from a previously scheduled shut down.\n \
Usage: worldshutdown [timer] [interval] - Shuts down the server and all zones after [timer] seconds and sends warning every [interval] seconds\n");
} else if(message->params_size() == 2 && ((time=atoi(message->params(0).c_str()))>0) && ((interval=atoi(message->params(1).c_str()))>0)) {
message->set_result(StringFormat("Sending shutdown packet now, World will shutdown in: %i minutes with an interval of: %i seconds", (time / 60), interval));
zoneserver_list.WorldShutDown(time, interval);
}
else if(strcasecmp(message->params(0).c_str(), "now") == 0){
message->set_result("Sending shutdown packet now");
zoneserver_list.WorldShutDown(0, 0);
}
else if(strcasecmp(message->params(0).c_str(), "disable") == 0){
message->set_result("Shutdown prevented, next time I may not be so forgiving...");
zoneserver_list.SendEmoteMessage(0, 0, 0, 15, "<SYSTEMWIDE MESSAGE>:SYSTEM MSG:World shutdown aborted.");
zoneserver_list.shutdowntimer->Disable();
zoneserver_list.reminder->Disable();
}
}
if (message->result().length() <= 1) {
message->set_result("Failed to parse command.");
}
if (!message->SerializeToString(&pubMessage)) {
Log(Logs::General, Logs::NATS, "Failed to serialize command message to string");
return;
}
s = natsConnection_PublishString(conn, reply, pubMessage.c_str());
if (s != NATS_OK) {
Log(Logs::General, Logs::NATS, "Failed to send CommandMessageEvent");
return;
}
}
//Send a message to all zone servers.
void NatsManager::ChannelMessageEvent(eqproto::ChannelMessage* message) {
if (!connect()) return;
if (message->zone_id() > 0) return; //do'nt process non-zero messages
Log(Logs::General, Logs::NATS, "Broadcasting Message");
if (message->is_emote()) { //emote message
zoneserver_list.SendEmoteMessage(message->to().c_str(), message->guilddbid(), message->minstatus(), message->type(), message->message().c_str());
return;
}
//normal broadcast
char tmpname[64];
tmpname[0] = '*';
strcpy(&tmpname[1], message->from().c_str());
//TODO: add To support on tells
int channel = message->chan_num();
if (channel < 1) channel = 5; //default to ooc
zoneserver_list.SendChannelMessage(tmpname, 0, channel, message->language(), message->message().c_str());
}
void NatsManager::Save()
{
return;
}
void NatsManager::Load()
{
if (!connect()) return;
s = natsConnection_SubscribeSync(&channelMessageSub, conn, "ChannelMessageWorld");
s = natsConnection_SubscribeSync(&commandMessageSub, conn, "CommandMessageWorld");
return;
}

43
world/nats_manager.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef NATS_H
#define NATS_H
#include "nats.h"
#include "world_config.h"
#include "../common/global_define.h"
#include "../common/types.h"
#include "../common/timer.h"
#ifndef PROTO_H
#define PROTO_H
#include "../common/proto/message.pb.h"
#endif
#include "../common/servertalk.h"
class NatsManager
{
public:
NatsManager();
~NatsManager();
void Process();
void OnChannelMessage(ServerChannelMessage_Struct * msg);
void OnEmoteMessage(ServerEmoteMessage_Struct * msg);
void SendAdminMessage(std::string adminMessage);
void ChannelMessageEvent(eqproto::ChannelMessage* message);
void CommandMessageEvent(eqproto::CommandMessage* message, const char* reply);
void SendChannelMessage(eqproto::ChannelMessage* message);
void Save();
void Load();
protected:
bool connect();
Timer nats_timer;
natsConnection *conn = NULL;
natsStatus s;
natsStatistics *stats = NULL;
natsOptions *opts = NULL;
natsSubscription *channelMessageSub = NULL;
natsSubscription *commandMessageSub = NULL;
natsSubscription *adminMessageSub = NULL;
};
#endif

View File

@ -83,6 +83,7 @@ union semun {
#include "queryserv.h"
#include "web_interface.h"
#include "console.h"
#include "nats_manager.h"
#include "../common/net/servertalk_server.h"
@ -102,6 +103,7 @@ bool holdzones = false;
const WorldConfig *Config;
EQEmuLogSys LogSys;
WebInterfaceList web_interface;
NatsManager nats;
void CatchSignal(int sig_num);
void CheckForServerScript(bool force_download = false);
@ -386,6 +388,7 @@ int main(int argc, char** argv) {
adventure_manager.Load();
adventure_manager.LoadLeaderboardInfo();
nats.Load();
Log(Logs::General, Logs::World_Server, "Purging expired instances");
database.PurgeExpiredInstances();
@ -412,7 +415,7 @@ int main(int argc, char** argv) {
server_opts.credentials = Config->SharedKey;
server_connection->Listen(server_opts);
Log(Logs::General, Logs::World_Server, "Server (TCP) listener started.");
nats.SendAdminMessage("World server booted up.");
server_connection->OnConnectionIdentified("Zone", [&console](std::shared_ptr<EQ::Net::ServertalkServerConnection> connection) {
LogF(Logs::General, Logs::World_Server, "New Zone Server connection from {2} at {0}:{1}",
connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID());
@ -559,6 +562,7 @@ int main(int argc, char** argv) {
launcher_list.Process();
LFPGroupList.Process();
adventure_manager.Process();
nats.Process();
if (InterserverTimer.Check()) {
InterserverTimer.Start();

View File

@ -35,6 +35,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "adventure_manager.h"
#include "ucs.h"
#include "queryserv.h"
#include "nats_manager.h"
extern ClientList client_list;
extern GroupLFPList LFPGroupList;
@ -44,6 +45,7 @@ extern volatile bool RunLoops;
extern AdventureManager adventure_manager;
extern UCSConnection UCSLink;
extern QueryServConnection QSLink;
extern NatsManager nats;
void CatchSignal(int sig_num);
ZoneServer::ZoneServer(std::shared_ptr<EQ::Net::ServertalkServerConnection> connection, EQ::Net::ConsoleServer *console)
@ -413,6 +415,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
UCSLink.SendMessage(scm->from, scm->message);
break;
}
nats.OnChannelMessage(scm);
if (scm->chan_num == 7 || scm->chan_num == 14) {
if (scm->deliverto[0] == '*') {
@ -505,6 +508,7 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) {
}
case ServerOP_EmoteMessage: {
ServerEmoteMessage_Struct* sem = (ServerEmoteMessage_Struct*)pack->pBuffer;
nats.OnEmoteMessage(sem);
zoneserver_list.SendEmoteMessageRaw(sem->to, sem->guilddbid, sem->minstatus, sem->type, sem->message);
break;
}

View File

@ -61,7 +61,7 @@ SET(zone_sources
lua_raid.cpp
lua_spawn.cpp
lua_spell.cpp
lua_stat_bonuses.cpp
lua_stat_bonuses.cpp
embperl.cpp
embxs.cpp
entity.cpp
@ -80,6 +80,7 @@ SET(zone_sources
mob.cpp
mob_ai.cpp
mod_functions.cpp
nats_manager.cpp
net.cpp
npc.cpp
npc_ai.cpp
@ -187,13 +188,14 @@ SET(zone_headers
lua_raid.h
lua_spawn.h
lua_spell.h
lua_stat_bonuses.h
lua_stat_bonuses.h
map.h
masterentity.h
maxskill.h
message.h
merc.h
mob.h
nats_manager.h
net.h
npc.h
npc_ai.h

View File

@ -32,6 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "worldserver.h"
#include "zone.h"
#include "lua_parser.h"
#include "nats_manager.h"
#include <assert.h>
#include <stdio.h>
@ -52,6 +53,7 @@ extern WorldServer worldserver;
extern EntityList entity_list;
extern Zone* zone;
extern NatsManager nats;
EQEmu::skills::SkillType Mob::AttackAnimation(int Hand, const EQEmu::ItemInstance* weapon, EQEmu::skills::SkillType skillinuse)
{
@ -2232,7 +2234,7 @@ bool NPC::Death(Mob* killer_mob, int32 damage, uint16 spell, EQEmu::skills::Skil
entity_list.QueueClients(killer_mob, app, false);
safe_delete(app);
nats.OnDeathEvent(d);
if (respawn2) {
respawn2->DeathReset(1);
}
@ -2816,6 +2818,7 @@ void Mob::DamageShield(Mob* attacker, bool spell_ds) {
cds->damage = DS;
entity_list.QueueCloseClients(this, outapp);
safe_delete(outapp);
nats.OnDamageEvent(cds->source, cds);
}
else if (DS > 0 && !spell_ds) {
//we are healing the attacker...
@ -3740,7 +3743,7 @@ void Mob::CommonDamage(Mob* attacker, int &damage, const uint16 spell_id, const
CastToClient()->QueuePacket(outapp);
}
}
nats.OnDamageEvent(a->source, a);
safe_delete(outapp);
}
else {

View File

@ -59,6 +59,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "water_map.h"
#include "worldserver.h"
#include "zone.h"
#include "nats_manager.h"
#ifdef BOTS
#include "bot.h"
@ -70,6 +71,8 @@ extern volatile bool is_zone_loaded;
extern WorldServer worldserver;
extern PetitionList petition_list;
extern EntityList entity_list;
extern NatsManager nats;
typedef void (Client::*ClientPacketProc)(const EQApplicationPacket *app);
//Use a map for connecting opcodes since it dosent get used a lot and is sparse
@ -1262,6 +1265,8 @@ void Client::Handle_Connect_OP_ZoneEntry(const EQApplicationPacket *app)
struct in_addr ghost_addr;
ghost_addr.s_addr = eqs->GetRemoteIP();
nats.SendAdminMessage(StringFormat("Ghosting client: Account ID:%i Name:%s Character:%s IP:%s",
client->AccountID(), client->AccountName(), client->GetName(), inet_ntoa(ghost_addr)));
Log(Logs::General, Logs::Error, "Ghosting client: Account ID:%i Name:%s Character:%s IP:%s",
client->AccountID(), client->AccountName(), client->GetName(), inet_ntoa(ghost_addr));
client->Save();
@ -2931,7 +2936,7 @@ void Client::Handle_OP_Assist(const EQApplicationPacket *app)
}
}
}
nats.OnEntityEvent(OP_Assist, this->GetID(), eid->entity_id);
FastQueuePacket(&outapp);
return;
}
@ -3978,6 +3983,7 @@ void Client::Handle_OP_Camp(const EQApplicationPacket *app)
if (IsLFP())
worldserver.StopLFP(CharacterID());
nats.OnEntityEvent(OP_Camp, this->GetID(), 0);
if (GetGM())
{
OnDisconnect(true);
@ -4203,7 +4209,7 @@ void Client::Handle_OP_ChannelMessage(const EQApplicationPacket *app)
Message(13, "You try to speak but cant move your mouth!");
return;
}
nats.OnChannelMessageEvent(this->GetID(), cm);
ChannelMessageReceived(cm->chan_num, cm->language, cm->skill_in_language, cm->message, cm->targetname);
return;
}
@ -5165,6 +5171,7 @@ void Client::Handle_OP_Damage(const EQApplicationPacket *app)
CombatDamage_Struct* damage = (CombatDamage_Struct*)app->pBuffer;
//dont send to originator of falling damage packets
entity_list.QueueClients(this, app, (damage->type == DamageTypeFalling));
nats.OnDamageEvent(damage->source, damage);
return;
}
@ -5913,6 +5920,7 @@ void Client::Handle_OP_GMBecomeNPC(const EQApplicationPacket *app)
if (this->Admin() < minStatusToUseGMCommands) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(this->account_name, this->name, "/becomenpc");
nats.SendAdminMessage(StringFormat("Hacker %s /becomenpc attempt.", GetCleanName()));
return;
}
if (app->size != sizeof(BecomeNPC_Struct)) {
@ -5944,6 +5952,7 @@ void Client::Handle_OP_GMDelCorpse(const EQApplicationPacket *app)
if (this->Admin() < commandEditPlayerCorpses) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(this->account_name, this->name, "/delcorpse");
nats.SendAdminMessage(StringFormat("Hacker %s /delcorpse attempt.", GetCleanName()));
return;
}
GMDelCorpse_Struct* dc = (GMDelCorpse_Struct *)app->pBuffer;
@ -5965,6 +5974,7 @@ void Client::Handle_OP_GMEmoteZone(const EQApplicationPacket *app)
if (this->Admin() < minStatusToUseGMCommands) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(this->account_name, this->name, "/emote");
nats.SendAdminMessage(StringFormat("Hacker %s /emote attempt.", GetCleanName()));
return;
}
if (app->size != sizeof(GMEmoteZone_Struct)) {
@ -5998,6 +6008,7 @@ void Client::Handle_OP_GMFind(const EQApplicationPacket *app)
if (this->Admin() < minStatusToUseGMCommands) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(this->account_name, this->name, "/find");
nats.SendAdminMessage(StringFormat("Hacker %s /find attempt.", GetCleanName()));
return;
}
if (app->size != sizeof(GMSummon_Struct)) {
@ -6036,6 +6047,7 @@ void Client::Handle_OP_GMGoto(const EQApplicationPacket *app)
if (this->Admin() < minStatusToUseGMCommands) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(this->account_name, this->name, "/goto");
nats.SendAdminMessage(StringFormat("Hacker %s /goto attempt.", GetCleanName()));
return;
}
GMSummon_Struct* gmg = (GMSummon_Struct*)app->pBuffer;
@ -6063,6 +6075,7 @@ void Client::Handle_OP_GMHideMe(const EQApplicationPacket *app)
if (this->Admin() < minStatusToUseGMCommands) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(this->account_name, this->name, "/hideme");
nats.SendAdminMessage(StringFormat("Hacker %s /hideme attempt.", GetCleanName()));
return;
}
if (app->size != sizeof(SpawnAppearance_Struct)) {
@ -6083,6 +6096,7 @@ void Client::Handle_OP_GMKick(const EQApplicationPacket *app)
if (this->Admin() < minStatusToKick) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(this->account_name, this->name, "/kick");
nats.SendAdminMessage(StringFormat("Hacker %s /kick attempt.", GetCleanName()));
return;
}
GMKick_Struct* gmk = (GMKick_Struct *)app->pBuffer;
@ -6113,6 +6127,7 @@ void Client::Handle_OP_GMKill(const EQApplicationPacket *app)
if (this->Admin() < minStatusToUseGMCommands) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(this->account_name, this->name, "/kill");
nats.SendAdminMessage(StringFormat("Hacker %s /kill attempt.", GetCleanName()));
return;
}
if (app->size != sizeof(GMKill_Struct)) {
@ -6165,6 +6180,7 @@ void Client::Handle_OP_GMLastName(const EQApplicationPacket *app)
if (this->Admin() < minStatusToUseGMCommands) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(client->account_name, client->name, "/lastname");
nats.SendAdminMessage(StringFormat("Hacker %s /lastname attempt.", GetCleanName()));
return;
}
else
@ -6190,6 +6206,7 @@ void Client::Handle_OP_GMNameChange(const EQApplicationPacket *app)
if (this->Admin() < minStatusToUseGMCommands) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(this->account_name, this->name, "/name");
nats.SendAdminMessage(StringFormat("Hacker %s /name attempt.", GetCleanName()));
return;
}
Client* client = entity_list.GetClientByName(gmn->oldname);
@ -6334,6 +6351,7 @@ void Client::Handle_OP_GMToggle(const EQApplicationPacket *app)
if (this->Admin() < minStatusToUseGMCommands) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(this->account_name, this->name, "/toggle");
nats.SendAdminMessage(StringFormat("Hacker %s /toggle attempt.", GetCleanName()));
return;
}
GMToggle_Struct *ts = (GMToggle_Struct *)app->pBuffer;
@ -6385,6 +6403,7 @@ void Client::Handle_OP_GMZoneRequest(const EQApplicationPacket *app)
if (this->Admin() < minStatusToBeGM) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(this->account_name, this->name, "/zone");
nats.SendAdminMessage(StringFormat("Hacker %s /zone attempt.", GetCleanName()));
return;
}
@ -6433,6 +6452,7 @@ void Client::Handle_OP_GMZoneRequest2(const EQApplicationPacket *app)
if (this->Admin() < minStatusToBeGM) {
Message(13, "Your account has been reported for hacking.");
database.SetHackerFlag(this->account_name, this->name, "/zone");
nats.SendAdminMessage(StringFormat("Hacker %s /zone attempt.", GetCleanName()));
return;
}
if (app->size < sizeof(uint32)) {

View File

@ -45,6 +45,7 @@
#include "../common/string_util.h"
#include "event_codes.h"
#include "guild_mgr.h"
#include "nats_manager.h"
#include "map.h"
#include "petitions.h"
#include "queryserv.h"
@ -60,6 +61,7 @@ extern volatile bool is_zone_loaded;
extern WorldServer worldserver;
extern PetitionList petition_list;
extern EntityList entity_list;
extern NatsManager nats;
bool Client::Process() {
bool ret = true;
@ -2199,7 +2201,7 @@ void Client::ClearHover()
EQApplicationPacket *outapp = MakeBuffsPacket(false);
CastToClient()->FastQueuePacket(&outapp);
}
nats.OnSpawnEvent(OP_ZoneEntry, this->GetID(), &sze->player.spawn);
dead = false;
}

View File

@ -67,10 +67,12 @@
#include "titles.h"
#include "water_map.h"
#include "worldserver.h"
#include "nats_manager.h"
extern QueryServ* QServ;
extern WorldServer worldserver;
extern TaskManager *taskmanager;
extern NatsManager nats;
void CatchSignal(int sig_num);
@ -563,6 +565,8 @@ int command_realdispatch(Client *c, const char *message)
QServ->PlayerLogEvent(Player_Log_Issued_Commands, c->CharacterID(), event_desc);
}
nats.SendAdminMessage(StringFormat("%s in %s issued command: %s", c->GetCleanName(), database.GetZoneName(zone->GetZoneID()), message));
if(cur->access >= COMMANDS_LOGGING_MIN_STATUS) {
Log(Logs::General, Logs::Commands, "%s (%s) used command: %s (target=%s)", c->GetName(), c->AccountName(), message, c->GetTarget()?c->GetTarget()->GetName():"NONE");
}

View File

@ -4879,3 +4879,16 @@ void EntityList::ReloadMerchants() {
}
}
}
std::map<uint16, NPC *> EntityList::ListNPCs()
{
std::map<uint16, NPC*> npcs;
auto it = npc_list.begin();
while (it != npc_list.end()) {
NPC *n = it->second;
npcs[n->id] = n;
++it;
}
return npcs;
}

View File

@ -216,6 +216,7 @@ public:
return it->second;
return nullptr;
}
std::map<uint16, NPC*> ListNPCs();
Doors *GetDoorsByDoorID(uint32 id);
Doors *GetDoorsByDBID(uint32 id);
void RemoveAllCorpsesByCharID(uint32 charid);

View File

@ -23,8 +23,10 @@
#include "quest_parser_collection.h"
#include "worldserver.h"
#include "zonedb.h"
#include "nats_manager.h"
extern WorldServer worldserver;
extern NatsManager nats;
// @merth: this needs to be touched up
uint32 Client::NukeItem(uint32 itemnum, uint8 where_to_check) {
@ -626,6 +628,7 @@ void Client::DropItem(int16 slot_id, bool recurse)
invalid_drop = nullptr;
database.SetHackerFlag(this->AccountName(), this->GetCleanName(), "Tried to drop an item on the ground that was nodrop!");
nats.SendAdminMessage(StringFormat("Hacker %s: Tried to drop nodrop item on ground", GetCleanName()));
GetInv().DeleteItem(slot_id);
return;
}

View File

@ -26,6 +26,7 @@
#include "mob.h"
#include "npc.h"
#include "zonedb.h"
#include "nats_manager.h"
#include <iostream>
#include <stdlib.h>
@ -34,6 +35,8 @@
#define snprintf _snprintf
#endif
extern NatsManager nats;
// Queries the loottable: adds item & coin to the npc
void ZoneDatabase::AddLootTableToNPC(NPC* npc,uint32 loottable_id, ItemList* itemlist, uint32* copper, uint32* silver, uint32* gold, uint32* plat) {
const LootTable_Struct* lts = nullptr;
@ -242,6 +245,7 @@ void NPC::AddLootDrop(const EQEmu::ItemData *item2, ItemList* itemlist, int16 ch
wc = (WearChange_Struct*)outapp->pBuffer;
wc->spawn_id = GetID();
wc->material=0;
nats.OnWearChangeEvent(this->GetID(), wc);
}
item->item_id = item2->ID;

9
zone/lua.hpp Normal file
View File

@ -0,0 +1,9 @@
// lua.hpp
// Lua header files for C++
// <<extern "C">> not supplied automatically because Lua also compiles as C++
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}

File diff suppressed because it is too large Load Diff

View File

@ -30,40 +30,41 @@
#define BEST_Z_INVALID -99999
extern const ZoneConfig *Config;
class Map
namespace EQEmu
{
public:
Map();
~Map();
class Map
{
public:
Map();
~Map();
float FindBestZ(glm::vec3 &start, glm::vec3 *result) const;
float FindClosestZ(glm::vec3 &start, glm::vec3 *result) const;
bool LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const;
bool LineIntersectsZoneNoZLeaps(glm::vec3 start, glm::vec3 end, float step_mag, glm::vec3 *result) const;
bool CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const;
float FindBestZ(glm::vec3 &start, glm::vec3 *result) const;
float FindClosestZ(glm::vec3 &start, glm::vec3 *result) const;
bool LineIntersectsZone(glm::vec3 start, glm::vec3 end, float step, glm::vec3 *result) const;
bool LineIntersectsZoneNoZLeaps(glm::vec3 start, glm::vec3 end, float step_mag, glm::vec3 *result) const;
bool CheckLoS(glm::vec3 myloc, glm::vec3 oloc) const;
#ifdef USE_MAP_MMFS
bool Load(std::string filename, bool force_mmf_overwrite = false);
bool Load(std::string filename, bool force_mmf_overwrite = false);
#else
bool Load(std::string filename);
bool Load(std::string filename);
#endif
static Map *LoadMapFile(std::string file);
private:
void RotateVertex(glm::vec3 &v, float rx, float ry, float rz);
void ScaleVertex(glm::vec3 &v, float sx, float sy, float sz);
void TranslateVertex(glm::vec3 &v, float tx, float ty, float tz);
bool LoadV1(FILE *f);
bool LoadV2(FILE *f);
static Map *LoadMapFile(std::string file);
private:
void RotateVertex(glm::vec3 &v, float rx, float ry, float rz);
void ScaleVertex(glm::vec3 &v, float sx, float sy, float sz);
void TranslateVertex(glm::vec3 &v, float tx, float ty, float tz);
bool LoadV1(FILE *f);
bool LoadV2(FILE *f);
#ifdef USE_MAP_MMFS
bool LoadMMF(const std::string& map_file_name, bool force_mmf_overwrite);
bool SaveMMF(const std::string& map_file_name, bool force_mmf_overwrite);
bool LoadMMF(const std::string& map_file_name, bool force_mmf_overwrite);
bool SaveMMF(const std::string& map_file_name, bool force_mmf_overwrite);
#endif /*USE_MAP_MMFS*/
struct impl;
impl *imp;
};
struct impl;
impl *imp;
};
}
#endif

View File

@ -23,6 +23,7 @@
#include "quest_parser_collection.h"
#include "string_ids.h"
#include "worldserver.h"
#include "nats_manager.h"
#include <limits.h>
#include <math.h>
@ -37,6 +38,7 @@ extern EntityList entity_list;
extern Zone* zone;
extern WorldServer worldserver;
extern NatsManager nats;
Mob::Mob(const char* in_name,
const char* in_lastname,
@ -944,7 +946,7 @@ void Mob::CreateSpawnPacket(EQApplicationPacket* app, Mob* ForWho) {
memset(app->pBuffer, 0, app->size);
NewSpawn_Struct* ns = (NewSpawn_Struct*)app->pBuffer;
FillSpawnStruct(ns, ForWho);
nats.OnSpawnEvent(OP_NewSpawn, ns->spawn.spawnId, &ns->spawn);
if(RuleB(NPC, UseClassAsLastName) && strlen(ns->spawn.lastName) == 0)
{
switch(ns->spawn.class_)
@ -1260,6 +1262,7 @@ void Mob::CreateDespawnPacket(EQApplicationPacket* app, bool Decay)
ds->spawn_id = GetID();
// The next field only applies to corpses. If 0, they vanish instantly, otherwise they 'decay'
ds->Decay = Decay ? 1 : 0;
nats.OnDeleteSpawnEvent(this->GetID(), ds);
}
void Mob::CreateHPPacket(EQApplicationPacket* app)
@ -1270,7 +1273,7 @@ void Mob::CreateHPPacket(EQApplicationPacket* app)
app->pBuffer = new uchar[app->size];
memset(app->pBuffer, 0, sizeof(SpawnHPUpdate_Struct2));
SpawnHPUpdate_Struct2* ds = (SpawnHPUpdate_Struct2*)app->pBuffer;
nats.OnHPEvent(OP_MobHealth, this->GetID(), cur_hp, max_hp);
ds->spawn_id = GetID();
// they don't need to know the real hp
ds->hp = (int)GetHPRatio();
@ -1304,7 +1307,7 @@ void Mob::CreateHPPacket(EQApplicationPacket* app)
// sends hp update of this mob to people who might care
void Mob::SendHPUpdate(bool skip_self /*= false*/, bool force_update_all /*= false*/)
{
nats.OnHPEvent(OP_HPUpdate, this->GetID(), cur_hp, max_hp);
/* If our HP is different from last HP update call - let's update ourself */
if (IsClient()) {
if (cur_hp != last_hp || force_update_all) {
@ -1467,7 +1470,7 @@ void Mob::SendPosition() {
else {
entity_list.QueueCloseClients(this, app, true, RuleI(Range, MobPositionUpdates), nullptr, false);
}
nats.OnClientUpdateEvent(this->GetID(), spu);
safe_delete(app);
}
@ -1481,7 +1484,7 @@ void Mob::SendPositionUpdateToClient(Client *client) {
MakeSpawnUpdateNoDelta(spawn_update);
client->QueuePacket(app, false);
nats.OnClientUpdateEvent(this->GetID(), spawn_update);
safe_delete(app);
}
@ -1504,6 +1507,7 @@ void Mob::SendPositionUpdate(uint8 iSendToSelf) {
else {
entity_list.QueueCloseClients(this, app, (iSendToSelf == 0), RuleI(Range, MobPositionUpdates), nullptr, false);
}
nats.OnClientUpdateEvent(this->GetID(), spu);
safe_delete(app);
}
@ -1622,7 +1626,7 @@ void Mob::DoAnim(const int animnum, int type, bool ackreq, eqFilterType filter)
ackreq, /* Packet ACK */
filter /* eqFilterType filter */
);
nats.OnAnimationEvent(this->GetID(), anim);
safe_delete(outapp);
}
@ -2899,7 +2903,7 @@ void Mob::SendWearChange(uint8 material_slot, Client *one_client)
{
one_client->QueuePacket(outapp, false, Client::CLIENT_CONNECTED);
}
nats.OnWearChangeEvent(this->GetID(), wc);
safe_delete(outapp);
}
@ -2923,6 +2927,7 @@ void Mob::SendTextureWC(uint8 slot, uint16 texture, uint32 hero_forge_model, uin
entity_list.QueueClients(this, outapp);
nats.OnWearChangeEvent(this->GetID(), wc);
safe_delete(outapp);
}
@ -2945,6 +2950,7 @@ void Mob::SetSlotTint(uint8 material_slot, uint8 red_tint, uint8 green_tint, uin
wc->wear_slot_id = material_slot;
entity_list.QueueClients(this, outapp);
nats.OnWearChangeEvent(this->GetID(), wc);
safe_delete(outapp);
}
@ -2962,6 +2968,7 @@ void Mob::WearChange(uint8 material_slot, uint16 texture, uint32 color, uint32 h
wc->wear_slot_id = material_slot;
entity_list.QueueClients(this, outapp);
nats.OnWearChangeEvent(this->GetID(), wc);
safe_delete(outapp);
}
@ -4688,7 +4695,9 @@ void Mob::DoKnockback(Mob *caster, uint32 pushback, uint32 pushup)
outapp_push->priority = 6;
entity_list.QueueClients(this, outapp_push, true);
CastToClient()->FastQueuePacket(&outapp_push);
nats.OnClientUpdateEvent(this->GetID(), spu);
}
}
void Mob::TrySpellOnKill(uint8 level, uint16 spell_id)

867
zone/nats_manager.cpp Normal file
View File

@ -0,0 +1,867 @@
#include "entity.h"
#include "mob.h"
//#include "client.h" //map error
#include "event_codes.h"
#include "nats.h"
#include "zone_config.h"
#include "nats_manager.h"
//#include "guild_mgr.h" //used for database, map error
#include "npc.h"
#include "../common/opcodemgr.h"
#include "../common/eqemu_logsys.h"
#include "../common/string_util.h"
#ifndef PROTO_H
#define PROTO_H
#include "../common/proto/message.pb.h"
#endif
const ZoneConfig *zoneConfig;
NatsManager::NatsManager()
{
//new timers, object initialization
zoneConfig = ZoneConfig::get();
}
NatsManager::~NatsManager()
{
nats_timer.Disable();
// Destroy all our objects to avoid report of memory leak
natsConnection_Destroy(conn);
natsOptions_Destroy(opts);
// To silence reports of memory still in used with valgrind
nats_Close();
}
void NatsManager::Process()
{
if (zoneSub == NULL) {
return;
}
if (!connect()) return;
natsMsg *msg = NULL;
s = NATS_OK;
std::string pubMessage;
for (int count = 0; (s == NATS_OK) && count < 100; count++)
{
s = natsSubscription_NextMsg(&msg, zoneSub, 1);
if (s != NATS_OK) break;
Log(Logs::General, Logs::NATS, "got message '%s'", natsMsg_GetData(msg));
natsMsg_Destroy(msg);
}
s = NATS_OK;
for (int count = 0; (s == NATS_OK) && count < 5; count++)
{
s = natsSubscription_NextMsg(&msg, commandMessageSub, 1);
if (s != NATS_OK) break;
Log(Logs::General, Logs::World_Server, "NATS Got Command Message '%s'", natsMsg_GetData(msg));
eqproto::CommandMessage message;
if (!message.ParseFromString(natsMsg_GetData(msg))) {
Log(Logs::General, Logs::World_Server, "Failed to marshal");
natsMsg_Destroy(msg);
continue;
}
if (message.command().compare("npctypespawn") == 0) {
if (message.params_size() < 2) {
message.set_result("Usage: !npctypespawn <npctypeid> <factionid> <x> <y> <z> <h>.");
} 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("spawn") == 0) {
if (message.params_size() < 5) {
message.set_result("Usage: npctypespawn <x> <y> <z> <h> 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 <entityid> <x> <y> <z> <h>.");
}
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 <entityid> <targetentityid> <hateamount>.");
}
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 <typeid>.");
}
else {
auto entities = eqproto::Entities();
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_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 <typeid>.");
}
}
}
if (message.result().length() < 1) {
message.set_result("Failed to parse command.");
}
if (!message.SerializeToString(&pubMessage)) {
Log(Logs::General, Logs::World_Server, "NATS Failed to serialize command message to string");
return;
}
s = natsConnection_PublishString(conn, natsMsg_GetReply(msg), pubMessage.c_str());
if (s != NATS_OK) {
Log(Logs::General, Logs::World_Server, "NATS Failed to send CommandMessageEvent");
return;
}
}
}
//Unregister is called when a zone is being put to sleep or being swapped
void NatsManager::Unregister()
{
if (!connect()) return;
if (commandMessageSub != NULL) {
s = natsSubscription_Unsubscribe(commandMessageSub);
commandMessageSub = NULL;
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "unsubscribe from commandMessageSub failed: %s", nats_GetLastError(&s));
}
if (zoneChannelMessageSub != NULL) {
s = natsSubscription_Unsubscribe(zoneChannelMessageSub);
zoneChannelMessageSub = NULL;
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "unsubscribe from zoneChannelMessageSub failed: %s", nats_GetLastError(&s));
}
if (zoneEntityEventSubscribeAllSub != NULL) {
s = natsSubscription_Unsubscribe(zoneEntityEventSubscribeAllSub);
zoneEntityEventSubscribeAllSub = NULL;
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "unsubscribe from zoneEntityEventSubscribeAllSub failed: %s", nats_GetLastError(&s));
}
if (zoneEntityEventSubscribeSub != NULL) {
s = natsSubscription_Unsubscribe(zoneEntityEventSubscribeSub);
zoneEntityEventSubscribeSub = NULL;
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "unsubscribe from zoneEntityEventSubscribeSub failed: %s", nats_GetLastError(&s));
}
if (zoneEntityEventListSub != NULL) {
s = natsSubscription_Unsubscribe(zoneEntityEventListSub);
zoneEntityEventListSub = NULL;
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "unsubscribe from zoneEntityEventListSub failed: %s", nats_GetLastError(&s));
}
if (zoneEntityEventSub != NULL) {
s = natsSubscription_Unsubscribe(zoneEntityEventSub);
zoneEntityEventSub = NULL;
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "unsubscribe from zoneEntityEventSub failed: %s", nats_GetLastError(&s));
}
Log(Logs::General, Logs::NATS, "unsubscribed from %s", subscribedZonename.c_str());
subscribedZonename.clear();
return;
}
void NatsManager::ZoneSubscribe(const char* zonename) {
if (strcmp(subscribedZonename.c_str(), zonename) == 0) return;
if (!connect()) return;
Unregister();
subscribedZonename = std::string(zonename);
s = natsConnection_SubscribeSync(&zoneChannelMessageSub, conn, StringFormat("zone.%s.channel_message", subscribedZonename.c_str()).c_str());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "failed to subscribe to zoneChannelMessageSub %s", nats_GetLastError(&s));
s = natsSubscription_SetPendingLimits(zoneChannelMessageSub, -1, -1);
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "failed to set pending limits to zoneChannelMessageSub %s", nats_GetLastError(&s));
s = natsConnection_SubscribeSync(&commandMessageSub, conn, StringFormat("zone.%s.command_message", subscribedZonename.c_str()).c_str());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "failed to subscribe to commandMessageSub %s", nats_GetLastError(&s));
s = natsSubscription_SetPendingLimits(commandMessageSub, -1, -1);
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "failed to set pending limits to commandMessageSub %s", nats_GetLastError(&s));
s = natsConnection_SubscribeSync(&zoneEntityEventSubscribeAllSub, conn, StringFormat("zone.%s.entity.event_subscribe.all", subscribedZonename.c_str()).c_str());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "failed to subscribe to zoneEntityEventSubscribeAllSub %s", nats_GetLastError(&s));
s = natsSubscription_SetPendingLimits(zoneEntityEventSubscribeAllSub, -1, -1);
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "failed to set pending limits to zoneEntityEventSubscribeAllSub %s", nats_GetLastError(&s));
s = natsConnection_SubscribeSync(&zoneEntityEventSubscribeAllSub, conn, StringFormat("zone.%s.entity.event_subscribe.all", subscribedZonename.c_str()).c_str());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "failed to subscribe to zoneEntityEventSubscribeAllSub %s", nats_GetLastError(&s));
s = natsSubscription_SetPendingLimits(zoneEntityEventSubscribeAllSub, -1, -1);
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "failed to set pending limits to zoneEntityEventSubscribeAllSub %s", nats_GetLastError(&s));
Log(Logs::General, Logs::NATS, "subscribed to %s", subscribedZonename.c_str());
}
void NatsManager::SendAdminMessage(std::string adminMessage) {
if (!connect()) return;
eqproto::ChannelMessage message;
message.set_message(adminMessage.c_str());
std::string pubMessage;
if (!message.SerializeToString(&pubMessage)) {
Log(Logs::General, Logs::NATS, "Failed to serialize message to string");
return;
}
s = natsConnection_PublishString(conn, "NATS AdminMessage", pubMessage.c_str());
if (s != NATS_OK) {
Log(Logs::General, Logs::NATS, "Failed to SendAdminMessage");
}
Log(Logs::General, Logs::NATS, "AdminMessage: %s", adminMessage.c_str());
}
bool NatsManager::connect() {
auto ncs = natsConnection_Status(conn);
if (ncs == CONNECTED) return true;
if (nats_timer.Enabled() && !nats_timer.Check()) return false;
natsOptions *opts = NULL;
natsOptions_Create(&opts);
natsOptions_SetMaxReconnect(opts, 0);
natsOptions_SetReconnectWait(opts, 0);
natsOptions_SetAllowReconnect(opts, false);
//The timeout is going to cause a 100ms delay on all connected clients every X seconds (20s)
//since this blocks the connection. It can be set lower or higher delay,
//but since NATS is a second priority I wanted server impact minimum.
natsOptions_SetTimeout(opts, 100);
std::string connection = StringFormat("nats://%s:%d", zoneConfig->NATSHost.c_str(), zoneConfig->NATSPort);
if (zoneConfig->NATSHost.length() == 0) connection = "nats://localhost:4222";
natsOptions_SetURL(opts, connection.c_str());
s = natsConnection_Connect(&conn, opts);
natsOptions_Destroy(opts);
if (s != NATS_OK) {
Log(Logs::General, Logs::NATS, "failed to connect to %s: %s, retrying in 20s", connection.c_str(), nats_GetLastError(&s));
conn = NULL;
nats_timer.Enable();
nats_timer.SetTimer(20000);
return false;
}
Log(Logs::General, Logs::NATS, "connected to %s", connection.c_str());
nats_timer.Disable();
return true;
}
void NatsManager::Load()
{
if (!connect()) return;
s = natsConnection_SubscribeSync(&zoneSub, conn, "zone");
if (s != NATS_OK) {
Log(Logs::General, Logs::NATS, "failed to subscribe to zone: %s", nats_GetLastError(&s));
return;
}
s = natsSubscription_SetPendingLimits(zoneSub, -1, -1);
if (s != NATS_OK) {
Log(Logs::General, Logs::NATS, "failed to set pending limits while subscribed to zone %s", nats_GetLastError(&s));
return;
}
s = natsConnection_SubscribeSync(&commandMessageSub, conn, "zone.command_message");
if (s != NATS_OK) {
Log(Logs::General, Logs::NATS, "failed to subscribe to commandMessageSub: %s", nats_GetLastError(&s));
return;
}
s = natsSubscription_SetPendingLimits(commandMessageSub, -1, -1);
if (s != NATS_OK) {
Log(Logs::General, Logs::NATS, "failed to set pending limits while subscribed to commandMessageSub: %s", nats_GetLastError(&s));
return;
}
s = natsConnection_SubscribeSync(&channelMessageSub, conn, "zone.channel_message");
if (s != NATS_OK) {
Log(Logs::General, Logs::NATS, "failed to subscribe to channel message: %s", nats_GetLastError(&s));
return;
}
s = natsSubscription_SetPendingLimits(channelMessageSub, -1, -1);
if (s != NATS_OK) {
Log(Logs::General, Logs::NATS, "failed to set pending limits while subscribed to channel message: %s", nats_GetLastError(&s));
return;
}
return;
}
void NatsManager::DailyGain(int account_id, int character_id, const char* identity, int levels_gained, int experience_gained, int money_earned)
{
if (!connect()) return;
eqproto::DailyGain daily;
daily.set_account_id(account_id);
daily.set_character_id(character_id);
daily.set_identity(identity);
daily.set_levels_gained(levels_gained);
daily.set_experience_gained(experience_gained);
daily.set_money_earned(money_earned);
std::string pubMessage;
if (!daily.SerializeToString(&pubMessage)) {
Log(Logs::General, Logs::NATS, "failed to serialize dailygain to string");
return;
}
s = natsConnection_PublishString(conn, "DailyGain", pubMessage.c_str());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "failed to send DailyGain: %s", nats_GetLastError(&s));
}
/*
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;
return false;
}
void NatsManager::OnDeathEvent(Death_Struct* d) {
if (!connect()) return;
if (d == NULL) return;
if (!isEntityEventAllEnabled && !isEntitySubscribed(d->spawn_id)) return;
std::string pubMessage;
auto event = eqproto::DeathEvent();
event.set_spawn_id(d->spawn_id);
event.set_killer_id(d->killer_id);
event.set_bind_zone_id(d->bindzoneid);
event.set_spell_id(d->spell_id);
event.set_attack_skill_id(d->attack_skill);
event.set_damage(d->damage);
if (!event.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
auto finalEvent = eqproto::Event();
finalEvent.set_payload(pubMessage.c_str());
finalEvent.set_op(eqproto::OP_Death);
if (!finalEvent.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
s = natsConnection_Publish(conn, StringFormat("zone.%s.entity.event.%d", subscribedZonename.c_str(), d->spawn_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "Failed to send EntityEvent");
}
void NatsManager::OnChannelMessageEvent(uint32 entity_id, ChannelMessage_Struct* cm) {
if (!connect()) return;
if (entity_id == 0) return;
if (!isEntityEventAllEnabled && !isEntitySubscribed(entity_id)) return;
std::string pubMessage;
auto event = eqproto::ChannelMessageEvent();
event.set_target_name(cm->targetname);
event.set_sender(cm->sender);
event.set_language(cm->language);
event.set_chan_num(cm->chan_num);
event.set_cm_unknown4(*cm->cm_unknown4);
event.set_skill_in_language(cm->skill_in_language);
event.set_message(cm->message);
if (!event.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
auto finalEvent = eqproto::Event();
finalEvent.set_payload(pubMessage.c_str());
finalEvent.set_op(eqproto::OP_ChannelMessage);
if (!finalEvent.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
s = natsConnection_Publish(conn, StringFormat("zone.%s.entity.event.%d", subscribedZonename.c_str(), entity_id).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) {
if (!connect()) return;
if (entity_id == 0) return;
if (!isEntityEventAllEnabled && !isEntitySubscribed(entity_id)) return;
std::string pubMessage;
auto event = eqproto::EntityEvent();
event.set_entity_id(entity_id);
event.set_target_id(target_id);
if (!event.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
auto finalEvent = eqproto::Event();
finalEvent.set_payload(pubMessage.c_str());
if (op == OP_Camp) finalEvent.set_op(eqproto::OP_Camp);
else if (op == OP_Assist) finalEvent.set_op(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, "Failed to serialize message to string"); return; }
s = natsConnection_Publish(conn, StringFormat("zone.%s.entity.event.%d", subscribedZonename.c_str(), entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "Failed to send EntityEvent");
}
void NatsManager::OnSpawnEvent(const EmuOpcode op, uint32 entity_id, Spawn_Struct *spawn) {
if (!connect()) return;
if (entity_id == 0) return;
if (!isEntityEventAllEnabled && !isEntitySubscribed(entity_id)) return;
std::string pubMessage;
auto event = eqproto::SpawnEvent();
event.set_unknown0000(spawn->unknown0000);
event.set_gm(spawn->gm);
event.set_unknown0003(spawn->unknown0003);
event.set_aaitle(spawn->aaitle);
event.set_unknown0004(spawn->unknown0004);
event.set_anon(spawn->anon);
event.set_face(spawn->face);
event.set_name(spawn->name);
event.set_deity(spawn->deity);
event.set_unknown0073(spawn->unknown0073);
event.set_size(spawn->size);
event.set_unknown0079(spawn->unknown0079);
event.set_npc(spawn->NPC);
event.set_invis(spawn->invis);
event.set_haircolor(spawn->haircolor);
event.set_curhp(spawn->curHp);
event.set_max_hp(spawn->max_hp);
event.set_findable(spawn->findable);
event.set_unknown0089(*spawn->unknown0089);
event.set_deltaheading(spawn->deltaHeading);
event.set_x(spawn->x);
event.set_padding0054(spawn->padding0054);
event.set_y(spawn->y);
event.set_animation(spawn->animation);
event.set_padding0058(spawn->padding0058);
event.set_z(spawn->z);
event.set_deltay(spawn->deltaY);
event.set_deltax(spawn->deltaX);
event.set_heading(spawn->heading);
event.set_padding0066(spawn->padding0066);
event.set_deltaz(spawn->deltaZ);
event.set_padding0070(spawn->padding0070);
event.set_eyecolor1(spawn->eyecolor1);
event.set_unknown0115(*spawn->unknown0115);
event.set_standstate(spawn->StandState);
event.set_drakkin_heritage(spawn->drakkin_heritage);
event.set_drakkin_tattoo(spawn->drakkin_tattoo);
event.set_drakkin_details(spawn->drakkin_details);
event.set_showhelm(spawn->showhelm);
event.set_unknown0140(*spawn->unknown0140);
event.set_is_npc(spawn->is_npc);
event.set_hairstyle(spawn->hairstyle);
event.set_beard(spawn->beard);
event.set_unknown0147(*spawn->unknown0147);
event.set_level(spawn->level);
event.set_playerstate(spawn->PlayerState);
event.set_beardcolor(spawn->beardcolor);
event.set_suffix(spawn->suffix);
event.set_petownerid(spawn->petOwnerId);
event.set_guildrank(spawn->guildrank);
event.set_unknown0194(*spawn->unknown0194);
/*auto texture = eqproto::Texture();
texture.set_elitemodel(spawn->equipment.Arms.EliteModel);
texture.set_herosforgemodel(spawn->equipment.Arms.HerosForgeModel);
texture.set_material(spawn->equipment.Arms.Material);
texture.set_unknown1(spawn->equipment.Arms.Unknown1);
texture.set_unknown2(spawn->equipment.Arms.Unknown2);
event.set_allocated_equipment(textureProfile);*/
event.set_runspeed(spawn->runspeed);
event.set_afk(spawn->afk);
event.set_guildid(spawn->guildID);
event.set_title(spawn->title);
event.set_unknown0274(spawn->unknown0274);
event.set_set_to_0xff(*spawn->set_to_0xFF);
event.set_helm(spawn->helm);
event.set_race(spawn->race);
event.set_unknown0288(spawn->unknown0288);
event.set_lastname(spawn->lastName);
event.set_walkspeed(spawn->walkspeed);
event.set_unknown0328(spawn->unknown0328);
event.set_is_pet(spawn->is_pet);
event.set_light(spawn->light);
event.set_class_(spawn->class_);
event.set_eyecolor2(spawn->eyecolor2);
event.set_flymode(spawn->flymode);
event.set_gender(spawn->gender);
event.set_bodytype(spawn->bodytype);
event.set_unknown0336(*spawn->unknown0336);
event.set_equip_chest2(spawn->equip_chest2);
event.set_mount_color(spawn->mount_color);
event.set_spawnid(spawn->spawnId);
event.set_unknown0344(*spawn->unknown0344);
event.set_ismercenary(spawn->IsMercenary);
//event.set_equipment_tint(spawn->equipment_tint);
event.set_lfg(spawn->lfg);
event.set_destructibleobject(spawn->DestructibleObject);
event.set_destructiblemodel(spawn->DestructibleModel);
event.set_destructiblename2(spawn->DestructibleName2);
event.set_destructiblestring(spawn->DestructibleString);
event.set_destructibleappearance(spawn->DestructibleAppearance);
event.set_destructibleunk1(spawn->DestructibleUnk1);
event.set_destructibleid1(spawn->DestructibleID1);
event.set_destructibleid2(spawn->DestructibleID2);
event.set_destructibleid3(spawn->DestructibleID3);
event.set_destructibleid4(spawn->DestructibleID4);
event.set_destructibleunk2(spawn->DestructibleUnk2);
event.set_destructibleunk3(spawn->DestructibleUnk3);
event.set_destructibleunk4(spawn->DestructibleUnk4);
event.set_destructibleunk5(spawn->DestructibleUnk5);
event.set_destructibleunk6(spawn->DestructibleUnk6);
event.set_destructibleunk7(spawn->DestructibleUnk7);
event.set_destructibleunk8(spawn->DestructibleUnk8);
event.set_destructibleunk9(spawn->DestructibleUnk9);
event.set_targetable_with_hotkey(spawn->targetable_with_hotkey);
event.set_show_name(spawn->show_name);
if (!event.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
auto finalEvent = eqproto::Event();
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);
else { Log(Logs::General, Logs::NATS, "unhandled op type passed: %i", op); return; }
if (!finalEvent.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
s = natsConnection_Publish(conn, StringFormat("zone.%s.entity.event.%d", subscribedZonename.c_str(), entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "Failed to send EntityEvent");
}
void NatsManager::OnWearChangeEvent(uint32 entity_id, WearChange_Struct *wc) {
if (!connect()) return;
if (entity_id == 0) return;
if (!isEntityEventAllEnabled && !isEntitySubscribed(entity_id)) return;
std::string pubMessage;
auto event = eqproto::WearChangeEvent();
event.set_spawn_id(wc->spawn_id);
event.set_material(wc->material);
event.set_unknown06(wc->unknown06);
event.set_elite_material(wc->elite_material);
event.set_hero_forge_model(wc->hero_forge_model);
event.set_unknown18(wc->unknown18);
//event.set_color(wc->color); //tint
event.set_wear_slot_id(wc->wear_slot_id);
if (!event.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
auto finalEvent = eqproto::Event();
finalEvent.set_payload(pubMessage.c_str());
finalEvent.set_op(eqproto::OP_WearChange);
if (!finalEvent.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
s = natsConnection_Publish(conn, StringFormat("zone.%s.entity.event.%d", subscribedZonename.c_str(), entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "Failed to send EntityEvent");
}
void NatsManager::OnDeleteSpawnEvent(uint32 entity_id, DeleteSpawn_Struct *ds) {
if (!connect()) return;
if (entity_id == 0) return;
if (!isEntityEventAllEnabled && !isEntitySubscribed(entity_id)) return;
std::string pubMessage;
auto event = eqproto::DeleteSpawnEvent();
event.set_spawn_id(ds->spawn_id);
event.set_decay(ds->Decay);
if (!event.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
auto finalEvent = eqproto::Event();
finalEvent.set_payload(pubMessage.c_str());
finalEvent.set_op(eqproto::OP_DeleteSpawn);
if (!finalEvent.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
s = natsConnection_Publish(conn, StringFormat("zone.%s.entity.event.%d", subscribedZonename.c_str(), entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "Failed to send EntityEvent");
}
void NatsManager::OnHPEvent(const EmuOpcode op, uint32 entity_id, uint32 cur_hp, uint32 max_hp) {
if (!connect()) return;
if (entity_id == 0) return;
if (!isEntityEventAllEnabled && !isEntitySubscribed(entity_id)) return;
if (cur_hp == max_hp) return;
std::string pubMessage;
auto event = eqproto::HPEvent();
event.set_spawn_id(entity_id);
event.set_cur_hp(cur_hp);
event.set_max_hp(max_hp);
if (!event.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
auto finalEvent = eqproto::Event();
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);
else { Log(Logs::General, Logs::NATS, "unhandled op type passed: %i", op); return; }
if (!finalEvent.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
s = natsConnection_Publish(conn, StringFormat("zone.%s.entity.event.%d", subscribedZonename.c_str(), entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "Failed to send EntityEvent");
}
void NatsManager::OnDamageEvent(uint32 entity_id, CombatDamage_Struct *cd) {
if (!connect()) return;
if (entity_id == 0) return;
if (!isEntityEventAllEnabled && !isEntitySubscribed(entity_id)) return;
std::string pubMessage;
auto event = eqproto::DamageEvent();
event.set_target(cd->target);
event.set_source(cd->source);
event.set_type(cd->type);
event.set_spellid(cd->spellid);
event.set_damage(cd->damage);
event.set_force(cd->force);
event.set_meleepush_xy(cd->meleepush_xy);
event.set_meleepush_z(cd->meleepush_z);
if (!event.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
auto finalEvent = eqproto::Event();
finalEvent.set_payload(pubMessage.c_str());
finalEvent.set_op(eqproto::OP_Damage);
if (!finalEvent.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
s = natsConnection_Publish(conn, StringFormat("zone.%s.entity.event.%d", subscribedZonename.c_str(), entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "Failed to send EntityEvent");
}
void NatsManager::OnClientUpdateEvent(uint32 entity_id, PlayerPositionUpdateServer_Struct * spu) {
if (!connect()) return;
if (entity_id == 0) return;
if (!isEntityEventAllEnabled && !isEntitySubscribed(entity_id)) return;
std::string pubMessage;
auto event = eqproto::PlayerPositionUpdateEvent();
event.set_spawn_id(spu->spawn_id);
event.set_delta_heading(spu->delta_heading);
event.set_x_pos(spu->x_pos);
event.set_padding0002(spu->padding0002);
event.set_y_pos(spu->y_pos);
event.set_animation(spu->animation);
event.set_padding0006(spu->padding0006);
event.set_z_pos(spu->z_pos);
event.set_delta_y(spu->delta_y);
event.set_delta_x(spu->delta_x);
event.set_heading(spu->heading);
event.set_padding0014(spu->padding0014);
event.set_delta_z(spu->delta_z);
event.set_padding0018(spu->padding0018);
if (!event.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
auto finalEvent = eqproto::Event();
finalEvent.set_payload(pubMessage.c_str());
finalEvent.set_op(eqproto::OP_ClientUpdate);
if (!finalEvent.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
s = natsConnection_Publish(conn, StringFormat("zone.%s.entity.event.%d", subscribedZonename.c_str(), entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "Failed to send EntityEvent");
}
void NatsManager::OnAnimationEvent(uint32 entity_id, Animation_Struct *anim) {
if (!connect()) return;
if (entity_id == 0) return;
if (!isEntityEventAllEnabled && !isEntitySubscribed(entity_id)) return;
std::string pubMessage;
auto event = eqproto::AnimationEvent();
event.set_spawnid(anim->spawnid);
event.set_speed(anim->speed);
event.set_action(anim->action);
if (!event.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
auto finalEvent = eqproto::Event();
finalEvent.set_payload(pubMessage.c_str());
finalEvent.set_op(eqproto::OP_Animation);
if (!finalEvent.SerializeToString(&pubMessage)) { Log(Logs::General, Logs::NATS, "Failed to serialize message to string"); return; }
s = natsConnection_Publish(conn, StringFormat("zone.%s.entity.event.%d", subscribedZonename.c_str(), entity_id).c_str(), (const void*)pubMessage.c_str(), pubMessage.length());
if (s != NATS_OK) Log(Logs::General, Logs::NATS, "Failed to send EntityEvent");
}

55
zone/nats_manager.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef _NATS_H
#define _NATS_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"
class NatsManager
{
public:
NatsManager();
~NatsManager();
void Process();
void Unregister();
void ZoneSubscribe(const char * zonename);
void Load();
void DailyGain(int account_id, int character_id, const char * identity, int levels_gained = 0, int experience_gained = 0, int money_earned = 0);
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);
void OnWearChangeEvent(uint32 entity_id, WearChange_Struct * wc);
void OnDeleteSpawnEvent(uint32 entity_id, DeleteSpawn_Struct * ds);
void OnHPEvent(const EmuOpcode op, uint32 entity_id, uint32 cur_hp, uint32 max_hp);
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);
protected:
bool connect();
Timer nats_timer;
bool isEntitySubscribed(const uint16 ID);
bool isEntityEventAllEnabled = true;
natsConnection *conn = NULL;
natsStatus s;
natsOptions *opts = NULL;
std::string subscribedZonename;
//global zone subscriptions
natsSubscription *zoneSub = NULL;
natsSubscription *channelMessageSub = NULL;
natsSubscription *commandMessageSub = NULL;
//zone specific subscriptions
natsSubscription *zoneChannelMessageSub = NULL;
natsSubscription *zoneCommandMessageSub = NULL;
natsSubscription *zoneEntityEventSubscribeAllSub = NULL;
natsSubscription *zoneEntityEventSubscribeSub = NULL;
natsSubscription *zoneEntityEventListSub = NULL;
natsSubscription *zoneEntityEventSub = NULL;
};
#endif

View File

@ -62,6 +62,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "embparser.h"
#include "lua_parser.h"
#include "questmgr.h"
#include "nats_manager.h"
#include "../common/event/event_loop.h"
#include "../common/event/timer.h"
@ -100,6 +101,8 @@ WorldServer worldserver;
uint32 numclients = 0;
char errorname[32];
extern Zone* zone;
NatsManager nats;
npcDecayTimes_Struct npcCorpseDecayTimes[100];
TitleManager title_manager;
QueryServ *QServ = 0;
@ -131,7 +134,7 @@ int main(int argc, char** argv) {
std::string filename = Config->MapDir;
filename += mapfile;
auto m = new Map();
auto m = new EQEmu::Map();
auto success = m->Load(filename, true);
delete m;
std::cout << mapfile.c_str() << " conversion " << (success ? "succeeded" : "failed") << std::endl;
@ -148,6 +151,7 @@ int main(int argc, char** argv) {
return 1;
}
Config = ZoneConfig::get();
nats.Load();
const char *zone_name;
uint32 instance_id = 0;
@ -510,10 +514,14 @@ int main(int argc, char** argv) {
entity_list.MobProcess();
entity_list.BeaconProcess();
entity_list.EncounterProcess();
if (zone->IsLoaded()) {
nats.ZoneSubscribe(zone->GetShortName());
nats.Process();
}
if (zone) {
if (!zone->Process()) {
Zone::Shutdown();
nats.Unregister();
}
}
@ -571,8 +579,10 @@ int main(int argc, char** argv) {
safe_delete(Config);
if (zone != 0)
if (zone != 0) {
Zone::Shutdown(true);
nats.Unregister();
}
//Fix for Linux world server problem.
safe_delete(taskmanager);
command_deinit();

View File

@ -30,6 +30,7 @@
#include "quest_parser_collection.h"
#include "string_ids.h"
#include "worldserver.h"
#include "nats_manager.h"
#include <math.h>
@ -42,6 +43,7 @@
extern Zone* zone;
extern volatile bool is_zone_loaded;
extern WorldServer worldserver;
extern NatsManager nats;
// the spell can still fail here, if the buff can't stack
@ -936,6 +938,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
Save();
safe_delete(action_packet);
safe_delete(message_packet);
nats.OnDamageEvent(cd->source, cd);
}
else
{
@ -987,6 +990,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
Save();
safe_delete(action_packet);
safe_delete(message_packet);
nats.OnDamageEvent(cd->source, cd);
}
}
else
@ -1025,6 +1029,7 @@ bool Mob::SpellEffect(Mob* caster, uint16 spell_id, float partial, int level_ove
Save();
safe_delete(action_packet);
safe_delete(message_packet);
nats.OnDamageEvent(cd->source, cd);
}
}
}

View File

@ -81,6 +81,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
#include "quest_parser_collection.h"
#include "string_ids.h"
#include "worldserver.h"
#include "nats_manager.h"
#include <assert.h>
#include <math.h>
@ -104,6 +105,7 @@ Copyright (C) 2001-2002 EQEMu Development Team (http://eqemu.org)
extern Zone* zone;
extern volatile bool is_zone_loaded;
extern WorldServer worldserver;
extern NatsManager nats;
using EQEmu::CastingSlot;
@ -252,6 +254,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
Log(Logs::General, Logs::Error, "HACKER: %s (account: %s) attempted to click an equip-only effect on item %s (id: %d) which they shouldn't be able to equip!",
CastToClient()->GetCleanName(), CastToClient()->AccountName(), itm->GetItem()->Name, itm->GetItem()->ID);
database.SetHackerFlag(CastToClient()->AccountName(), CastToClient()->GetCleanName(), "Clicking equip-only item with an invalid class");
nats.SendAdminMessage(StringFormat("Hacker %s: Clicking equip-only item with an invalid class.", GetCleanName()));
}
else {
Message_StringID(13, MUST_EQUIP_ITEM);
@ -264,6 +267,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
Log(Logs::General, Logs::Error, "HACKER: %s (account: %s) attempted to click a race/class restricted effect on item %s (id: %d) which they shouldn't be able to click!",
CastToClient()->GetCleanName(), CastToClient()->AccountName(), itm->GetItem()->Name, itm->GetItem()->ID);
database.SetHackerFlag(CastToClient()->AccountName(), CastToClient()->GetCleanName(), "Clicking race/class restricted item with an invalid class");
nats.SendAdminMessage(StringFormat("Hacker %s: Clicking race/class restricted item with invalid class.", GetCleanName()));
}
else {
if (CastToClient()->ClientVersion() >= EQEmu::versions::ClientVersion::RoF)
@ -284,6 +288,7 @@ bool Mob::CastSpell(uint16 spell_id, uint16 target_id, CastingSlot slot,
// They are attempting to cast a must equip clicky without having it equipped
Log(Logs::General, Logs::Error, "HACKER: %s (account: %s) attempted to click an equip-only effect on item %s (id: %d) without equiping it!", CastToClient()->GetCleanName(), CastToClient()->AccountName(), itm->GetItem()->Name, itm->GetItem()->ID);
database.SetHackerFlag(CastToClient()->AccountName(), CastToClient()->GetCleanName(), "Clicking equip-only item without equiping it");
nats.SendAdminMessage(StringFormat("Hacker %s: Clicking equip-only item without equipping it.", GetCleanName()));
}
else {
Message_StringID(13, MUST_EQUIP_ITEM);
@ -2727,7 +2732,7 @@ void Mob::BardPulse(uint16 spell_id, Mob *caster) {
}
safe_delete(message_packet);
safe_delete(packet);
nats.OnDamageEvent(cd->source, cd);
}
//we are done...
return;
@ -4047,7 +4052,8 @@ bool Mob::SpellOnTarget(uint16 spell_id, Mob *spelltar, bool reflect, bool use_r
);
}
safe_delete(action_packet);
safe_delete(message_packet);
safe_delete(message_packet);
nats.OnDamageEvent(cd->source, cd);
Log(Logs::Detail, Logs::Spells, "Cast of %d by %s on %s complete successfully.", spell_id, GetName(), spelltar->GetName());

View File

@ -25,7 +25,7 @@
#include "client.h"
#include "entity.h"
#include "mob.h"
#include "nats_manager.h"
#include "quest_parser_collection.h"
#include "string_ids.h"
#include "worldserver.h"
@ -34,6 +34,7 @@ class QueryServ;
extern WorldServer worldserver;
extern QueryServ* QServ;
extern NatsManager nats;
// The maximum amount of a single bazaar/barter transaction expressed in copper.
// Equivalent to 2 Million plat
@ -1658,6 +1659,7 @@ void Client::BuyTraderItem(TraderBuy_Struct* tbs, Client* Trader, const EQApplic
if(!TakeMoneyFromPP(TotalCost)) {
database.SetHackerFlag(account_name, name, "Attempted to buy something in bazaar but did not have enough money.");
nats.SendAdminMessage(StringFormat("Hacker %s: Attempted to buy something in bazaar but did not have enough money.", GetCleanName()));
TradeRequestFailed(app);
safe_delete(outapp);
return;

View File

@ -23,8 +23,10 @@
#include "client.h"
#include "entity.h"
#include "mob.h"
#include "nats_manager.h"
#include "trap.h"
extern NatsManager nats;
/*
Schema:
@ -219,6 +221,7 @@ void Trap::Trigger(Mob* trigger)
a->type = 253;
trigger->CastToClient()->QueuePacket(outapp);
safe_delete(outapp);
nats.OnDamageEvent(a->source, a);
}
}

View File

@ -891,7 +891,7 @@ bool Zone::Init(bool iStaticZone) {
}
}
zone->zonemap = Map::LoadMapFile(zone->map_name);
zone->zonemap = EQEmu::Map::LoadMapFile(zone->map_name);
zone->watermap = WaterMap::LoadWaterMapfile(zone->map_name);
zone->pathing = PathManager::LoadPathFile(zone->map_name);

View File

@ -211,7 +211,7 @@ public:
void ReloadWorld(uint32 Option);
void ReloadMerchants();
Map* zonemap;
EQEmu::Map* zonemap;
WaterMap* watermap;
PathManager *pathing;
NewZone_Struct newzone_data;