mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-13 14:41:28 +00:00
[API] Implement Zone Sidecar (#3635)
* Zone sidecar work * Process management work * Merge * Sidecar work * API config option * Request proxy work * Proxy headers and params * Change port * Remove code * Sim work * Sidecar work * Update loot_simulator_controller.cpp * Update loot_simulator_controller.cpp * Formatting * Post merge change * Windows compile fix * Update sidecar_api.cpp * Update strings.cpp
This commit is contained in:
parent
0bbfcf7adc
commit
b027edd21e
@ -70,6 +70,7 @@ SET(common_sources
|
|||||||
perl_eqdb.cpp
|
perl_eqdb.cpp
|
||||||
perl_eqdb_res.cpp
|
perl_eqdb_res.cpp
|
||||||
process/process.cpp
|
process/process.cpp
|
||||||
|
process.cpp
|
||||||
proc_launcher.cpp
|
proc_launcher.cpp
|
||||||
profanity_manager.cpp
|
profanity_manager.cpp
|
||||||
ptimer.cpp
|
ptimer.cpp
|
||||||
@ -90,6 +91,7 @@ SET(common_sources
|
|||||||
timer.cpp
|
timer.cpp
|
||||||
unix.cpp
|
unix.cpp
|
||||||
platform.cpp
|
platform.cpp
|
||||||
|
json/json.hpp
|
||||||
json/jsoncpp.cpp
|
json/jsoncpp.cpp
|
||||||
zone_store.cpp
|
zone_store.cpp
|
||||||
net/console_server.cpp
|
net/console_server.cpp
|
||||||
@ -583,6 +585,7 @@ SET(common_headers
|
|||||||
path_manager.cpp
|
path_manager.cpp
|
||||||
platform.h
|
platform.h
|
||||||
process/process.h
|
process/process.h
|
||||||
|
process.h
|
||||||
proc_launcher.h
|
proc_launcher.h
|
||||||
profanity_manager.h
|
profanity_manager.h
|
||||||
profiler.h
|
profiler.h
|
||||||
|
|||||||
@ -39,15 +39,15 @@ namespace EQEmuCommand {
|
|||||||
{
|
{
|
||||||
if (cmd[{"-d", "--debug"}]) {
|
if (cmd[{"-d", "--debug"}]) {
|
||||||
std::cout << "Positional args:\n";
|
std::cout << "Positional args:\n";
|
||||||
for (auto &pos_arg : cmd.pos_args())
|
for (auto &pos_arg: cmd.pos_args())
|
||||||
std::cout << '\t' << pos_arg << std::endl;
|
std::cout << '\t' << pos_arg << std::endl;
|
||||||
|
|
||||||
std::cout << "\nFlags:\n";
|
std::cout << "\nFlags:\n";
|
||||||
for (auto &flag : cmd.flags())
|
for (auto &flag: cmd.flags())
|
||||||
std::cout << '\t' << flag << std::endl;
|
std::cout << '\t' << flag << std::endl;
|
||||||
|
|
||||||
std::cout << "\nParameters:\n";
|
std::cout << "\nParameters:\n";
|
||||||
for (auto ¶m : cmd.params())
|
for (auto ¶m: cmd.params())
|
||||||
std::cout << '\t' << param.first << " : " << param.second << std::endl;
|
std::cout << '\t' << param.first << " : " << param.second << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,8 +69,8 @@ namespace EQEmuCommand {
|
|||||||
{
|
{
|
||||||
bool arguments_filled = true;
|
bool arguments_filled = true;
|
||||||
|
|
||||||
int index = 2;
|
int index = 2;
|
||||||
for (auto &arg : arguments) {
|
for (auto &arg: arguments) {
|
||||||
if (cmd(arg).str().empty() && cmd(index).str().empty()) {
|
if (cmd(arg).str().empty() && cmd(index).str().empty()) {
|
||||||
arguments_filled = false;
|
arguments_filled = false;
|
||||||
}
|
}
|
||||||
@ -79,12 +79,12 @@ namespace EQEmuCommand {
|
|||||||
|
|
||||||
if (!arguments_filled || (argc == 2 && !cmd[{"-h", "--help"}]) || (argc == 3 && cmd[{"-h", "--help"}])) {
|
if (!arguments_filled || (argc == 2 && !cmd[{"-h", "--help"}]) || (argc == 3 && cmd[{"-h", "--help"}])) {
|
||||||
std::string arguments_string;
|
std::string arguments_string;
|
||||||
for (auto &arg : arguments) {
|
for (auto &arg: arguments) {
|
||||||
arguments_string += " " + arg;
|
arguments_string += " " + arg;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string options_string;
|
std::string options_string;
|
||||||
for (auto &opt : options) {
|
for (auto &opt: options) {
|
||||||
options_string += " " + opt + "\n";
|
options_string += " " + opt + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,14 +124,6 @@ namespace EQEmuCommand {
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
std::string description;
|
std::string description;
|
||||||
bool ran_command = false;
|
|
||||||
for (auto &it: in_function_map) {
|
|
||||||
if (it.first == argv[1]) {
|
|
||||||
(it.second)(argc, argv, cmd, description);
|
|
||||||
ran_command = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cmd[{"-h", "--help"}]) {
|
if (cmd[{"-h", "--help"}]) {
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout <<
|
std::cout <<
|
||||||
@ -142,9 +134,7 @@ namespace EQEmuCommand {
|
|||||||
<< std::endl
|
<< std::endl
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
/**
|
// Get max command length for padding length
|
||||||
* Get max command length for padding length
|
|
||||||
*/
|
|
||||||
int max_command_length = 0;
|
int max_command_length = 0;
|
||||||
|
|
||||||
for (auto &it: in_function_map) {
|
for (auto &it: in_function_map) {
|
||||||
@ -155,18 +145,14 @@ namespace EQEmuCommand {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Display command menu
|
||||||
* Display command menu
|
|
||||||
*/
|
|
||||||
std::string command_section;
|
std::string command_section;
|
||||||
for (auto &it: in_function_map) {
|
for (auto &it: in_function_map) {
|
||||||
description.clear();
|
description.clear();
|
||||||
|
|
||||||
(it.second)(argc, argv, cmd, description);
|
(it.second)(argc, argv, cmd, description);
|
||||||
|
|
||||||
/**
|
// Print section header
|
||||||
* Print section header
|
|
||||||
*/
|
|
||||||
std::string command_prefix = it.first.substr(0, it.first.find(":"));
|
std::string command_prefix = it.first.substr(0, it.first.find(":"));
|
||||||
|
|
||||||
if (command_prefix.find("test") != std::string::npos) {
|
if (command_prefix.find("test") != std::string::npos) {
|
||||||
@ -178,9 +164,7 @@ namespace EQEmuCommand {
|
|||||||
std::cout << termcolor::reset << command_prefix << std::endl;
|
std::cout << termcolor::reset << command_prefix << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// Print commands
|
||||||
* Print commands
|
|
||||||
*/
|
|
||||||
std::stringstream command;
|
std::stringstream command;
|
||||||
command << termcolor::colorize << termcolor::yellow << it.first << termcolor::reset;
|
command << termcolor::colorize << termcolor::yellow << it.first << termcolor::reset;
|
||||||
printf(" %-*s %s\n", max_command_length, command.str().c_str(), description.c_str());
|
printf(" %-*s %s\n", max_command_length, command.str().c_str(), description.c_str());
|
||||||
@ -191,6 +175,15 @@ namespace EQEmuCommand {
|
|||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ran_command = false;
|
||||||
|
|
||||||
|
for (auto &it: in_function_map) {
|
||||||
|
if (it.first == argv[1]) {
|
||||||
|
(it.second)(argc, argv, cmd, description);
|
||||||
|
ran_command = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ran_command) {
|
if (ran_command) {
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
}
|
}
|
||||||
|
|||||||
24640
common/json/json.hpp
Normal file
24640
common/json/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -72,6 +72,8 @@ std::string GetPlatformName()
|
|||||||
return "HC";
|
return "HC";
|
||||||
case EQEmuExePlatform::ExePlatformTests:
|
case EQEmuExePlatform::ExePlatformTests:
|
||||||
return "Tests";
|
return "Tests";
|
||||||
|
case EQEmuExePlatform::ExePlatformZoneSidecar:
|
||||||
|
return "ZoneSidecar";
|
||||||
default:
|
default:
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,7 +37,8 @@ enum EQEmuExePlatform
|
|||||||
ExePlatformClientImport,
|
ExePlatformClientImport,
|
||||||
ExePlatformClientExport,
|
ExePlatformClientExport,
|
||||||
ExePlatformHC,
|
ExePlatformHC,
|
||||||
ExePlatformTests
|
ExePlatformTests,
|
||||||
|
ExePlatformZoneSidecar
|
||||||
};
|
};
|
||||||
|
|
||||||
void RegisterExecutablePlatform(EQEmuExePlatform p);
|
void RegisterExecutablePlatform(EQEmuExePlatform p);
|
||||||
|
|||||||
44
common/process.cpp
Normal file
44
common/process.cpp
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#include <string>
|
||||||
|
#include <fstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "process.h"
|
||||||
|
|
||||||
|
inline std::string random_string(size_t length)
|
||||||
|
{
|
||||||
|
auto randchar = []() -> char {
|
||||||
|
const char charset[] = "0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz";
|
||||||
|
const size_t max_index = (sizeof(charset) - 1);
|
||||||
|
return charset[static_cast<size_t>(std::rand()) % max_index];
|
||||||
|
};
|
||||||
|
std::string str(length, 0);
|
||||||
|
std::generate_n(str.begin(), length, randchar);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Process::execute(const std::string &cmd, bool return_result)
|
||||||
|
{
|
||||||
|
std::string random = "/tmp/" + random_string(25);
|
||||||
|
const char *file_name = random.c_str();
|
||||||
|
|
||||||
|
if (return_result) {
|
||||||
|
#ifdef _WINDOWS
|
||||||
|
std::system((cmd + " > " + file_name + " 2>&1").c_str());
|
||||||
|
#else
|
||||||
|
std::system((cmd + " > " + file_name + " 2>&1").c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
std::system((cmd).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
if (return_result) {
|
||||||
|
std::ifstream file(file_name);
|
||||||
|
result = {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
|
||||||
|
std::remove(file_name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
10
common/process.h
Normal file
10
common/process.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef EQEMU_PROCESS_H
|
||||||
|
#define EQEMU_PROCESS_H
|
||||||
|
|
||||||
|
class Process {
|
||||||
|
public:
|
||||||
|
static std::string execute(const std::string &cmd, bool return_result = true);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //EQEMU_PROCESS_H
|
||||||
@ -42,10 +42,32 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include <random>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
//Const char based
|
//Const char based
|
||||||
#include "strings_legacy.cpp" // legacy c functions
|
#include "strings_legacy.cpp" // legacy c functions
|
||||||
#include "strings_misc.cpp" // anything non "Strings" scoped
|
#include "strings_misc.cpp" // anything non "Strings" scoped
|
||||||
|
|
||||||
|
std::string Strings::Random(size_t length)
|
||||||
|
{
|
||||||
|
static auto &chrs = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||||
|
|
||||||
|
thread_local static std::mt19937 rg{std::random_device{}()};
|
||||||
|
|
||||||
|
thread_local static std::uniform_int_distribution<std::string::size_type> pick(0, sizeof(chrs) - 2);
|
||||||
|
|
||||||
|
std::string s;
|
||||||
|
|
||||||
|
s.reserve(length);
|
||||||
|
|
||||||
|
while (length--) {
|
||||||
|
s += chrs[pick(rg)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> Strings::Split(const std::string &str, const char delim)
|
std::vector<std::string> Strings::Split(const std::string &str, const char delim)
|
||||||
{
|
{
|
||||||
std::vector<std::string> ret;
|
std::vector<std::string> ret;
|
||||||
@ -64,7 +86,7 @@ std::vector<std::string> Strings::Split(const std::string &str, const char delim
|
|||||||
}
|
}
|
||||||
|
|
||||||
// this one takes delimiter length into consideration
|
// this one takes delimiter length into consideration
|
||||||
std::vector<std::string> Strings::Split(const std::string& s, const std::string& delimiter)
|
std::vector<std::string> Strings::Split(const std::string &s, const std::string &delimiter)
|
||||||
{
|
{
|
||||||
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
|
size_t pos_start = 0, pos_end, delim_len = delimiter.length();
|
||||||
std::string token;
|
std::string token;
|
||||||
@ -783,21 +805,6 @@ bool Strings::ToBool(const std::string& bool_string)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns a random string of specified length
|
|
||||||
std::string Strings::Random(size_t length)
|
|
||||||
{
|
|
||||||
auto randchar = []() -> char {
|
|
||||||
const char charset[] = "0123456789"
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
||||||
"abcdefghijklmnopqrstuvwxyz";
|
|
||||||
const size_t max_index = (sizeof(charset) - 1);
|
|
||||||
return charset[static_cast<size_t>(std::rand()) % max_index];
|
|
||||||
};
|
|
||||||
std::string str(length, 0);
|
|
||||||
std::generate_n(str.begin(), length, randchar);
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
// a wrapper for stoi which will return a fallback if the string
|
// a wrapper for stoi which will return a fallback if the string
|
||||||
// fails to cast to a number
|
// fails to cast to a number
|
||||||
int Strings::ToInt(const std::string &s, int fallback)
|
int Strings::ToInt(const std::string &s, int fallback)
|
||||||
|
|||||||
@ -185,7 +185,6 @@ public:
|
|||||||
value = strtod(tmp_str.data(), nullptr);
|
value = strtod(tmp_str.data(), nullptr);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::string StringFormat(const char *format, ...);
|
const std::string StringFormat(const char *format, ...);
|
||||||
|
|||||||
@ -133,6 +133,8 @@ SET(zone_sources
|
|||||||
quest_parser_collection.cpp
|
quest_parser_collection.cpp
|
||||||
raids.cpp
|
raids.cpp
|
||||||
raycast_mesh.cpp
|
raycast_mesh.cpp
|
||||||
|
sidecar_api/sidecar_api.cpp
|
||||||
|
sidecar_api/loot_simulator_controller.cpp
|
||||||
shared_task_zone_messaging.cpp
|
shared_task_zone_messaging.cpp
|
||||||
spawn2.cpp
|
spawn2.cpp
|
||||||
spawn2.h
|
spawn2.h
|
||||||
@ -253,6 +255,7 @@ SET(zone_headers
|
|||||||
quest_parser_collection.h
|
quest_parser_collection.h
|
||||||
raids.h
|
raids.h
|
||||||
raycast_mesh.h
|
raycast_mesh.h
|
||||||
|
sidecar_api/sidecar_api.h
|
||||||
shared_task_zone_messaging.h
|
shared_task_zone_messaging.h
|
||||||
spawn2.cpp
|
spawn2.cpp
|
||||||
spawn2.h
|
spawn2.h
|
||||||
@ -273,8 +276,9 @@ SET(zone_headers
|
|||||||
zone_config.h
|
zone_config.h
|
||||||
zonedb.h
|
zonedb.h
|
||||||
zonedump.h
|
zonedump.h
|
||||||
|
zone_cli.h
|
||||||
zone_reload.h
|
zone_reload.h
|
||||||
)
|
zone_cli.cpp)
|
||||||
|
|
||||||
ADD_EXECUTABLE(zone ${zone_sources} ${zone_headers})
|
ADD_EXECUTABLE(zone ${zone_sources} ${zone_headers})
|
||||||
|
|
||||||
|
|||||||
24
zone/cli/sidecar_serve_http.cpp
Normal file
24
zone/cli/sidecar_serve_http.cpp
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#include "../../common/http/httplib.h"
|
||||||
|
#include "../../common/eqemu_logsys.h"
|
||||||
|
#include "../sidecar_api/sidecar_api.h"
|
||||||
|
#include "../../common/platform.h"
|
||||||
|
|
||||||
|
void ZoneCLI::SidecarServeHttp(int argc, char **argv, argh::parser &cmd, std::string &description)
|
||||||
|
{
|
||||||
|
if (cmd[{"-h", "--help"}]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterExecutablePlatform(EQEmuExePlatform::ExePlatformZoneSidecar);
|
||||||
|
|
||||||
|
int port = 0;
|
||||||
|
std::string key;
|
||||||
|
if (!cmd("--port").str().empty()) {
|
||||||
|
port = strtoll(cmd("--port").str().c_str(), nullptr, 10);
|
||||||
|
}
|
||||||
|
if (!cmd("--key").str().empty()) {
|
||||||
|
key = cmd("--key").str();
|
||||||
|
}
|
||||||
|
|
||||||
|
SidecarApi::BootWebserver(port, key);
|
||||||
|
}
|
||||||
196
zone/main.cpp
196
zone/main.cpp
@ -68,6 +68,7 @@
|
|||||||
|
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include "../common/unix.h"
|
#include "../common/unix.h"
|
||||||
|
|
||||||
@ -85,6 +86,8 @@ extern volatile bool is_zone_loaded;
|
|||||||
#include "../common/events/player_event_logs.h"
|
#include "../common/events/player_event_logs.h"
|
||||||
#include "../common/path_manager.h"
|
#include "../common/path_manager.h"
|
||||||
#include "../common/database/database_update.h"
|
#include "../common/database/database_update.h"
|
||||||
|
#include "zone_event_scheduler.h"
|
||||||
|
#include "zone_cli.h"
|
||||||
|
|
||||||
EntityList entity_list;
|
EntityList entity_list;
|
||||||
WorldServer worldserver;
|
WorldServer worldserver;
|
||||||
@ -112,17 +115,23 @@ const ZoneConfig *Config;
|
|||||||
double frame_time = 0.0;
|
double frame_time = 0.0;
|
||||||
|
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void UpdateWindowTitle(char* iNewTitle);
|
void UpdateWindowTitle(char *iNewTitle);
|
||||||
void CatchSignal(int sig_num);
|
void CatchSignal(int sig_num);
|
||||||
|
|
||||||
extern void MapOpcodes();
|
extern void MapOpcodes();
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
RegisterExecutablePlatform(ExePlatformZone);
|
RegisterExecutablePlatform(ExePlatformZone);
|
||||||
LogSys.LoadLogSettingsDefaults();
|
LogSys.LoadLogSettingsDefaults();
|
||||||
|
|
||||||
set_exception_handler();
|
set_exception_handler();
|
||||||
|
|
||||||
|
// silence logging if we ran a command
|
||||||
|
if (ZoneCLI::RanConsoleCommand(argc, argv)) {
|
||||||
|
LogSys.SilenceConsoleLogging();
|
||||||
|
}
|
||||||
|
|
||||||
path.LoadPaths();
|
path.LoadPaths();
|
||||||
|
|
||||||
#ifdef USE_MAP_MMFS
|
#ifdef USE_MAP_MMFS
|
||||||
@ -154,77 +163,80 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
Config = ZoneConfig::get();
|
Config = ZoneConfig::get();
|
||||||
|
|
||||||
const char *zone_name;
|
// static zone booting
|
||||||
uint32 instance_id = 0;
|
const char *zone_name;
|
||||||
|
uint32 instance_id = 0;
|
||||||
std::string z_name;
|
std::string z_name;
|
||||||
if (argc == 4) {
|
if (!ZoneCLI::RanSidecarCommand(argc, argv)) {
|
||||||
instance_id = Strings::ToInt(argv[3]);
|
if (argc == 4) {
|
||||||
worldserver.SetLauncherName(argv[2]);
|
instance_id = Strings::ToInt(argv[3]);
|
||||||
auto zone_port = Strings::Split(argv[1], ':');
|
worldserver.SetLauncherName(argv[2]);
|
||||||
|
auto zone_port = Strings::Split(argv[1], ':');
|
||||||
|
|
||||||
if (!zone_port.empty()) {
|
if (!zone_port.empty()) {
|
||||||
z_name = zone_port[0];
|
z_name = zone_port[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (zone_port.size() > 1) {
|
||||||
|
std::string p_name = zone_port[1];
|
||||||
|
Config->SetZonePort(Strings::ToInt(p_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
worldserver.SetLaunchedName(z_name.c_str());
|
||||||
|
if (strncmp(z_name.c_str(), "dynamic_", 8) == 0) {
|
||||||
|
zone_name = ".";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
zone_name = z_name.c_str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (argc == 3) {
|
||||||
|
worldserver.SetLauncherName(argv[2]);
|
||||||
|
auto zone_port = Strings::Split(argv[1], ':');
|
||||||
|
|
||||||
if (zone_port.size() > 1) {
|
if (!zone_port.empty()) {
|
||||||
std::string p_name = zone_port[1];
|
z_name = zone_port[0];
|
||||||
Config->SetZonePort(Strings::ToInt(p_name));
|
}
|
||||||
|
|
||||||
|
if (zone_port.size() > 1) {
|
||||||
|
std::string p_name = zone_port[1];
|
||||||
|
Config->SetZonePort(Strings::ToInt(p_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
worldserver.SetLaunchedName(z_name.c_str());
|
||||||
|
if (strncmp(z_name.c_str(), "dynamic_", 8) == 0) {
|
||||||
|
zone_name = ".";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
zone_name = z_name.c_str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else if (argc == 2) {
|
||||||
|
worldserver.SetLauncherName("NONE");
|
||||||
|
auto zone_port = Strings::Split(argv[1], ':');
|
||||||
|
|
||||||
worldserver.SetLaunchedName(z_name.c_str());
|
if (!zone_port.empty()) {
|
||||||
if (strncmp(z_name.c_str(), "dynamic_", 8) == 0) {
|
z_name = zone_port[0];
|
||||||
zone_name = ".";
|
}
|
||||||
|
|
||||||
|
if (zone_port.size() > 1) {
|
||||||
|
std::string p_name = zone_port[1];
|
||||||
|
Config->SetZonePort(Strings::ToInt(p_name));
|
||||||
|
}
|
||||||
|
|
||||||
|
worldserver.SetLaunchedName(z_name.c_str());
|
||||||
|
if (strncmp(z_name.c_str(), "dynamic_", 8) == 0) {
|
||||||
|
zone_name = ".";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
zone_name = z_name.c_str();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
zone_name = z_name.c_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (argc == 3) {
|
|
||||||
worldserver.SetLauncherName(argv[2]);
|
|
||||||
auto zone_port = Strings::Split(argv[1], ':');
|
|
||||||
|
|
||||||
if (!zone_port.empty()) {
|
|
||||||
z_name = zone_port[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zone_port.size() > 1) {
|
|
||||||
std::string p_name = zone_port[1];
|
|
||||||
Config->SetZonePort(Strings::ToInt(p_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
worldserver.SetLaunchedName(z_name.c_str());
|
|
||||||
if (strncmp(z_name.c_str(), "dynamic_", 8) == 0) {
|
|
||||||
zone_name = ".";
|
zone_name = ".";
|
||||||
|
worldserver.SetLaunchedName(".");
|
||||||
|
worldserver.SetLauncherName("NONE");
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
zone_name = z_name.c_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (argc == 2) {
|
|
||||||
worldserver.SetLauncherName("NONE");
|
|
||||||
auto zone_port = Strings::Split(argv[1], ':');
|
|
||||||
|
|
||||||
if (!zone_port.empty()) {
|
|
||||||
z_name = zone_port[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (zone_port.size() > 1) {
|
|
||||||
std::string p_name = zone_port[1];
|
|
||||||
Config->SetZonePort(Strings::ToInt(p_name));
|
|
||||||
}
|
|
||||||
|
|
||||||
worldserver.SetLaunchedName(z_name.c_str());
|
|
||||||
if (strncmp(z_name.c_str(), "dynamic_", 8) == 0) {
|
|
||||||
zone_name = ".";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
zone_name = z_name.c_str();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
zone_name = ".";
|
|
||||||
worldserver.SetLaunchedName(".");
|
|
||||||
worldserver.SetLauncherName("NONE");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mutex = new Mutex;
|
auto mutex = new Mutex;
|
||||||
@ -235,7 +247,8 @@ int main(int argc, char** argv) {
|
|||||||
Config->DatabaseUsername.c_str(),
|
Config->DatabaseUsername.c_str(),
|
||||||
Config->DatabasePassword.c_str(),
|
Config->DatabasePassword.c_str(),
|
||||||
Config->DatabaseDB.c_str(),
|
Config->DatabaseDB.c_str(),
|
||||||
Config->DatabasePort)) {
|
Config->DatabasePort
|
||||||
|
)) {
|
||||||
LogError("Cannot continue without a database connection");
|
LogError("Cannot continue without a database connection");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -243,7 +256,7 @@ int main(int argc, char** argv) {
|
|||||||
// Multi-tenancy: Content Database
|
// Multi-tenancy: Content Database
|
||||||
if (!Config->ContentDbHost.empty()) {
|
if (!Config->ContentDbHost.empty()) {
|
||||||
if (!content_db.Connect(
|
if (!content_db.Connect(
|
||||||
Config->ContentDbHost.c_str() ,
|
Config->ContentDbHost.c_str(),
|
||||||
Config->ContentDbUsername.c_str(),
|
Config->ContentDbUsername.c_str(),
|
||||||
Config->ContentDbPassword.c_str(),
|
Config->ContentDbPassword.c_str(),
|
||||||
Config->ContentDbName.c_str(),
|
Config->ContentDbName.c_str(),
|
||||||
@ -280,7 +293,12 @@ int main(int argc, char** argv) {
|
|||||||
EQ::InitializeDynamicLookups();
|
EQ::InitializeDynamicLookups();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Register Log System and Settings */
|
// command handler
|
||||||
|
if (ZoneCLI::RanConsoleCommand(argc, argv) && !ZoneCLI::RanSidecarCommand(argc, argv)) {
|
||||||
|
LogSys.EnableConsoleLogging();
|
||||||
|
ZoneCLI::CommandHandler(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
LogSys.SetDatabase(&database)
|
LogSys.SetDatabase(&database)
|
||||||
->SetLogPath(path.GetLogPath())
|
->SetLogPath(path.GetLogPath())
|
||||||
->LoadLogDatabaseSettings()
|
->LoadLogDatabaseSettings()
|
||||||
@ -455,6 +473,11 @@ int main(int argc, char** argv) {
|
|||||||
worldserver.Connect();
|
worldserver.Connect();
|
||||||
worldserver.SetScheduler(&event_scheduler);
|
worldserver.SetScheduler(&event_scheduler);
|
||||||
|
|
||||||
|
// sidecar command handler
|
||||||
|
if (ZoneCLI::RanConsoleCommand(argc, argv) && ZoneCLI::RanSidecarCommand(argc, argv)) {
|
||||||
|
ZoneCLI::CommandHandler(argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
Timer InterserverTimer(INTERSERVER_TIMER); // does MySQL pings and auto-reconnect
|
Timer InterserverTimer(INTERSERVER_TIMER); // does MySQL pings and auto-reconnect
|
||||||
#ifdef EQPROFILE
|
#ifdef EQPROFILE
|
||||||
#ifdef PROFILE_DUMP_TIME
|
#ifdef PROFILE_DUMP_TIME
|
||||||
@ -486,13 +509,13 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
Timer quest_timers(100);
|
Timer quest_timers(100);
|
||||||
UpdateWindowTitle(nullptr);
|
UpdateWindowTitle(nullptr);
|
||||||
std::shared_ptr<EQStreamInterface> eqss;
|
std::shared_ptr<EQStreamInterface> eqss;
|
||||||
EQStreamInterface *eqsi;
|
EQStreamInterface *eqsi;
|
||||||
std::unique_ptr<EQ::Net::EQStreamManager> eqsm;
|
std::unique_ptr<EQ::Net::EQStreamManager> eqsm;
|
||||||
std::chrono::time_point<std::chrono::system_clock> frame_prev = std::chrono::system_clock::now();
|
std::chrono::time_point<std::chrono::system_clock> frame_prev = std::chrono::system_clock::now();
|
||||||
std::unique_ptr<EQ::Net::WebsocketServer> ws_server;
|
std::unique_ptr<EQ::Net::WebsocketServer> ws_server;
|
||||||
|
|
||||||
auto loop_fn = [&](EQ::Timer* t) {
|
auto loop_fn = [&](EQ::Timer *t) {
|
||||||
//Advance the timer to our current point in time
|
//Advance the timer to our current point in time
|
||||||
Timer::SetCurrentTime();
|
Timer::SetCurrentTime();
|
||||||
|
|
||||||
@ -520,12 +543,12 @@ int main(int argc, char** argv) {
|
|||||||
LogInfo("Starting EQ Network server on port [{}]", Config->ZonePort);
|
LogInfo("Starting EQ Network server on port [{}]", Config->ZonePort);
|
||||||
|
|
||||||
EQStreamManagerInterfaceOptions opts(Config->ZonePort, false, RuleB(Network, CompressZoneStream));
|
EQStreamManagerInterfaceOptions opts(Config->ZonePort, false, RuleB(Network, CompressZoneStream));
|
||||||
opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS);
|
opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS);
|
||||||
opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor);
|
opts.daybreak_options.resend_delay_factor = RuleR(Network, ResendDelayFactor);
|
||||||
opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS);
|
opts.daybreak_options.resend_delay_min = RuleI(Network, ResendDelayMinMS);
|
||||||
opts.daybreak_options.resend_delay_max = RuleI(Network, ResendDelayMaxMS);
|
opts.daybreak_options.resend_delay_max = RuleI(Network, ResendDelayMaxMS);
|
||||||
opts.daybreak_options.outgoing_data_rate = RuleR(Network, ClientDataRate);
|
opts.daybreak_options.outgoing_data_rate = RuleR(Network, ClientDataRate);
|
||||||
eqsm = std::make_unique<EQ::Net::EQStreamManager>(opts);
|
eqsm = std::make_unique<EQ::Net::EQStreamManager>(opts);
|
||||||
eqsf_open = true;
|
eqsf_open = true;
|
||||||
|
|
||||||
eqsm->OnNewConnection(
|
eqsm->OnNewConnection(
|
||||||
@ -546,7 +569,7 @@ int main(int argc, char** argv) {
|
|||||||
//check the stream identifier for any now-identified streams
|
//check the stream identifier for any now-identified streams
|
||||||
while ((eqsi = stream_identifier.PopIdentified())) {
|
while ((eqsi = stream_identifier.PopIdentified())) {
|
||||||
//now that we know what patch they are running, start up their client object
|
//now that we know what patch they are running, start up their client object
|
||||||
struct in_addr in;
|
struct in_addr in;
|
||||||
in.s_addr = eqsi->GetRemoteIP();
|
in.s_addr = eqsi->GetRemoteIP();
|
||||||
LogInfo("New client from [{}]:[{}]", inet_ntoa(in), ntohs(eqsi->GetRemotePort()));
|
LogInfo("New client from [{}]:[{}]", inet_ntoa(in), ntohs(eqsi->GetRemotePort()));
|
||||||
auto client = new Client(eqsi);
|
auto client = new Client(eqsi);
|
||||||
@ -558,7 +581,15 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (worldwasconnected && is_zone_loaded) {
|
if (worldwasconnected && is_zone_loaded) {
|
||||||
entity_list.ChannelMessageFromWorld(0, 0, ChatChannel_Broadcast, 0, 0, 100, "WARNING: World server connection lost");
|
entity_list.ChannelMessageFromWorld(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
ChatChannel_Broadcast,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
100,
|
||||||
|
"WARNING: World server connection lost"
|
||||||
|
);
|
||||||
worldwasconnected = false;
|
worldwasconnected = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -614,8 +645,9 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
safe_delete(Config);
|
safe_delete(Config);
|
||||||
|
|
||||||
if (zone != 0)
|
if (zone != 0) {
|
||||||
Zone::Shutdown(true);
|
Zone::Shutdown(true);
|
||||||
|
}
|
||||||
//Fix for Linux world server problem.
|
//Fix for Linux world server problem.
|
||||||
safe_delete(task_manager);
|
safe_delete(task_manager);
|
||||||
safe_delete(npc_scale_manager);
|
safe_delete(npc_scale_manager);
|
||||||
@ -638,7 +670,8 @@ void Shutdown()
|
|||||||
EQ::EventLoop::Get().Shutdown();
|
EQ::EventLoop::Get().Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CatchSignal(int sig_num) {
|
void CatchSignal(int sig_num)
|
||||||
|
{
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
LogInfo("Recieved signal: [{}]", sig_num);
|
LogInfo("Recieved signal: [{}]", sig_num);
|
||||||
#endif
|
#endif
|
||||||
@ -646,7 +679,8 @@ void CatchSignal(int sig_num) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update Window Title with relevant information */
|
/* Update Window Title with relevant information */
|
||||||
void UpdateWindowTitle(char* iNewTitle) {
|
void UpdateWindowTitle(char *iNewTitle)
|
||||||
|
{
|
||||||
#ifdef _WINDOWS
|
#ifdef _WINDOWS
|
||||||
char tmp[500];
|
char tmp[500];
|
||||||
if (iNewTitle) {
|
if (iNewTitle) {
|
||||||
|
|||||||
18
zone/sidecar_api/log_handler.cpp
Normal file
18
zone/sidecar_api/log_handler.cpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
void SidecarApi::RequestLogHandler(const httplib::Request &req, const httplib::Response &res)
|
||||||
|
{
|
||||||
|
if (!req.path.empty()) {
|
||||||
|
std::vector<std::string> params;
|
||||||
|
for (auto &p: req.params) {
|
||||||
|
params.emplace_back(fmt::format("{}={}", p.first, p.second));
|
||||||
|
}
|
||||||
|
|
||||||
|
LogInfo(
|
||||||
|
"[API] Request [{}] [{}{}] via [{}:{}]",
|
||||||
|
res.status,
|
||||||
|
req.path,
|
||||||
|
(!params.empty() ? "?" + Strings::Join(params, "&") : ""),
|
||||||
|
req.remote_addr,
|
||||||
|
req.remote_port
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
173
zone/sidecar_api/loot_simulator_controller.cpp
Normal file
173
zone/sidecar_api/loot_simulator_controller.cpp
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
#include "sidecar_api.h"
|
||||||
|
#include "../../common/json/json.hpp"
|
||||||
|
#include "../zone.h"
|
||||||
|
|
||||||
|
extern Zone* zone;
|
||||||
|
|
||||||
|
void SidecarApi::LootSimulatorController(const httplib::Request &req, httplib::Response &res)
|
||||||
|
{
|
||||||
|
int loottable_id = req.has_param("loottable_id") ? std::stoi(req.get_param_value("loottable_id")) : 4027;
|
||||||
|
int npc_id = req.has_param("npc_id") ? std::stoi(req.get_param_value("npc_id")) : 32040; // lord nagafen
|
||||||
|
auto iterations = 100;
|
||||||
|
auto log_enabled = false;
|
||||||
|
|
||||||
|
LogSys.log_settings[Logs::Loot].log_to_console = 0;
|
||||||
|
|
||||||
|
nlohmann::json j;
|
||||||
|
|
||||||
|
auto npc_type = content_db.LoadNPCTypesData(npc_id);
|
||||||
|
if (npc_type) {
|
||||||
|
auto npc = new NPC(
|
||||||
|
npc_type,
|
||||||
|
nullptr,
|
||||||
|
glm::vec4(0, 0, 0, 0),
|
||||||
|
GravityBehavior::Water
|
||||||
|
);
|
||||||
|
BenchTimer benchmark;
|
||||||
|
|
||||||
|
// depop the previous one
|
||||||
|
for (auto &n: entity_list.GetNPCList()) {
|
||||||
|
if (n.second->GetNPCTypeID() == npc_id) {
|
||||||
|
LogInfo("found npc id [{}]", npc_id);
|
||||||
|
n.second->Depop(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_list.Process();
|
||||||
|
entity_list.MobProcess();
|
||||||
|
npc->SetRecordLootStats(true);
|
||||||
|
|
||||||
|
for (int i = 0; i < iterations; i++) {
|
||||||
|
npc->AddLootTable(loottable_id);
|
||||||
|
|
||||||
|
for (auto &id: zone->GetGlobalLootTables(npc)) {
|
||||||
|
npc->AddLootTable(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entity_list.AddNPC(npc);
|
||||||
|
|
||||||
|
j["data"]["loottable_id"] = loottable_id;
|
||||||
|
j["data"]["npc_id"] = npc_id;
|
||||||
|
j["data"]["npc_name"] = npc->GetCleanName();
|
||||||
|
j["data"]["rolled_items_count"] = npc->GetRolledItems().size();
|
||||||
|
j["data"]["iterations"] = iterations;
|
||||||
|
|
||||||
|
// npc level loot table
|
||||||
|
auto loot_table = database.GetLootTable(loottable_id);
|
||||||
|
if (!loot_table) {
|
||||||
|
res.status = 400;
|
||||||
|
j["error"] = fmt::format("Loot table not found [{}]", loottable_id);
|
||||||
|
res.set_content(j.dump(), "application/json");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (uint32 i = 0; i < loot_table->NumEntries; i++) {
|
||||||
|
auto le = loot_table->Entries[i];
|
||||||
|
|
||||||
|
nlohmann::json jle;
|
||||||
|
jle["lootdrop_id"] = le.lootdrop_id;
|
||||||
|
jle["droplimit"] = le.droplimit;
|
||||||
|
jle["mindrop"] = le.mindrop;
|
||||||
|
jle["multiplier"] = le.multiplier;
|
||||||
|
jle["probability"] = le.probability;
|
||||||
|
|
||||||
|
auto loot_drop = database.GetLootDrop(le.lootdrop_id);
|
||||||
|
if (!loot_drop) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32 ei = 0; ei < loot_drop->NumEntries; ei++) {
|
||||||
|
auto e = loot_drop->Entries[ei];
|
||||||
|
int rolled_count = npc->GetRolledItemCount(e.item_id);
|
||||||
|
const EQ::ItemData *item = database.GetItem(e.item_id);
|
||||||
|
|
||||||
|
|
||||||
|
auto rolled_percentage = (float) ((float) ((float) rolled_count / (float) iterations) * 100);
|
||||||
|
|
||||||
|
nlohmann::json drop;
|
||||||
|
drop["slot"] = ei;
|
||||||
|
drop["item_id"] = e.item_id;
|
||||||
|
drop["item_name"] = item->Name;
|
||||||
|
drop["chance"] = fmt::format("{:.2f}", e.chance);
|
||||||
|
drop["simulate_rolled_count"] = rolled_count;
|
||||||
|
drop["simulate_rolled_percentage"] = fmt::format("{:.2f}", rolled_percentage);
|
||||||
|
jle["drops"].push_back(drop);
|
||||||
|
}
|
||||||
|
|
||||||
|
j["lootdrops"].push_back(jle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// global loot
|
||||||
|
for (auto &id: zone->GetGlobalLootTables(npc)) {
|
||||||
|
loot_table = database.GetLootTable(id);
|
||||||
|
if (!loot_table) {
|
||||||
|
LogInfo("Global Loot table not found [{}]", id);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32 i = 0; i < loot_table->NumEntries; i++) {
|
||||||
|
auto le = loot_table->Entries[i];
|
||||||
|
|
||||||
|
LogInfo(
|
||||||
|
"# Lootdrop ID [{}] drop_limit [{}] min_drop [{}] mult [{}] probability [{}]",
|
||||||
|
le.lootdrop_id,
|
||||||
|
le.droplimit,
|
||||||
|
le.mindrop,
|
||||||
|
le.multiplier,
|
||||||
|
le.probability
|
||||||
|
);
|
||||||
|
|
||||||
|
nlohmann::json jle;
|
||||||
|
jle["lootdrop_id"] = le.lootdrop_id;
|
||||||
|
jle["droplimit"] = le.droplimit;
|
||||||
|
jle["mindrop"] = le.mindrop;
|
||||||
|
jle["multiplier"] = le.multiplier;
|
||||||
|
jle["probability"] = le.probability;
|
||||||
|
|
||||||
|
auto loot_drop = database.GetLootDrop(le.lootdrop_id);
|
||||||
|
if (!loot_drop) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint32 ei = 0; ei < loot_drop->NumEntries; ei++) {
|
||||||
|
auto e = loot_drop->Entries[ei];
|
||||||
|
int rolled_count = npc->GetRolledItemCount(e.item_id);
|
||||||
|
const EQ::ItemData *item = database.GetItem(e.item_id);
|
||||||
|
|
||||||
|
auto rolled_percentage = (float) ((float) ((float) rolled_count / (float) iterations) *
|
||||||
|
100);
|
||||||
|
|
||||||
|
|
||||||
|
LogInfo(
|
||||||
|
"-- [{}] item_id [{}] chance [{}] rolled_count [{}] ({:.2f}%) name [{}]",
|
||||||
|
ei,
|
||||||
|
e.item_id,
|
||||||
|
e.chance,
|
||||||
|
rolled_count,
|
||||||
|
rolled_percentage,
|
||||||
|
item->Name
|
||||||
|
);
|
||||||
|
|
||||||
|
nlohmann::json drop;
|
||||||
|
drop["slot"] = ei;
|
||||||
|
drop["item_id"] = e.item_id;
|
||||||
|
drop["item_name"] = item->Name;
|
||||||
|
drop["chance"] = fmt::format("{:.2f}", e.chance);
|
||||||
|
drop["simulate_rolled_count"] = rolled_count;
|
||||||
|
drop["simulate_rolled_percentage"] = fmt::format("{:.2f}", rolled_percentage);
|
||||||
|
jle["drops"].push_back(drop);
|
||||||
|
|
||||||
|
j["global"]["lootdrops"].push_back(jle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j["data"]["time"] = benchmark.elapsed();
|
||||||
|
res.status = 200;
|
||||||
|
res.set_content(j.dump(), "application/json");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.status = 400;
|
||||||
|
j["error"] = fmt::format("Failed to spawn NPC ID [{}]", npc_id);
|
||||||
|
res.set_content(j.dump(), "application/json");
|
||||||
|
}
|
||||||
|
}
|
||||||
4
zone/sidecar_api/map_best_z_controller.cpp
Normal file
4
zone/sidecar_api/map_best_z_controller.cpp
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
void SidecarApi::MapBestZController(const httplib::Request &req, httplib::Response &res)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
119
zone/sidecar_api/sidecar_api.cpp
Normal file
119
zone/sidecar_api/sidecar_api.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
#include "sidecar_api.h"
|
||||||
|
#include "../../common/http/httplib.h"
|
||||||
|
#include "../../common/eqemu_logsys.h"
|
||||||
|
#include "../zonedb.h"
|
||||||
|
#include "../../shared_memory/loot.h"
|
||||||
|
#include "../../common/process.h"
|
||||||
|
#include "../common.h"
|
||||||
|
#include "../zone.h"
|
||||||
|
#include "../client.h"
|
||||||
|
#include "../../common/json/json.hpp"
|
||||||
|
#include <csignal>
|
||||||
|
|
||||||
|
void CatchSidecarSignal(int sig_num)
|
||||||
|
{
|
||||||
|
LogInfo("[SidecarAPI] Caught signal [{}]", sig_num);
|
||||||
|
LogInfo("Forcefully exiting for now");
|
||||||
|
std::exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "log_handler.cpp"
|
||||||
|
#include "test_controller.cpp"
|
||||||
|
#include "map_best_z_controller.cpp"
|
||||||
|
#include "../../common/file.h"
|
||||||
|
|
||||||
|
constexpr static int HTTP_RESPONSE_OK = 200;
|
||||||
|
constexpr static int HTTP_RESPONSE_BAD_REQUEST = 400;
|
||||||
|
constexpr static int HTTP_RESPONSE_UNAUTHORIZED = 401;
|
||||||
|
|
||||||
|
std::string authorization_key;
|
||||||
|
|
||||||
|
void SidecarApi::BootWebserver(int port, const std::string &key)
|
||||||
|
{
|
||||||
|
LogInfo("Booting zone sidecar API");
|
||||||
|
|
||||||
|
std::signal(SIGINT, CatchSidecarSignal);
|
||||||
|
std::signal(SIGTERM, CatchSidecarSignal);
|
||||||
|
std::signal(SIGKILL, CatchSidecarSignal);
|
||||||
|
|
||||||
|
if (!key.empty()) {
|
||||||
|
authorization_key = key;
|
||||||
|
LogInfo("Booting with authorization key [{}]", authorization_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
int web_api_port = port > 0 ? port : 9099;
|
||||||
|
std::string hotfix_name = "zonesidecar_api_";
|
||||||
|
|
||||||
|
// bake shared memory if it doesn't exist
|
||||||
|
// TODO: Windows
|
||||||
|
if (!File::Exists("shared/zonesidecar_api_loot_drop")) {
|
||||||
|
LogInfo("Creating shared memory for prefix [{}]", hotfix_name);
|
||||||
|
|
||||||
|
std::string output = Process::execute(
|
||||||
|
fmt::format(
|
||||||
|
"./bin/shared_memory -hotfix={} loot items",
|
||||||
|
hotfix_name
|
||||||
|
)
|
||||||
|
);
|
||||||
|
std::cout << output << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
LogInfo("Loading loot tables");
|
||||||
|
if (!database.LoadLoot(hotfix_name)) {
|
||||||
|
LogError("Loading loot failed!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// bootup a fake zone
|
||||||
|
Zone::Bootup(ZoneID("qrg"), 0, false);
|
||||||
|
zone->StopShutdownTimer();
|
||||||
|
|
||||||
|
httplib::Server api;
|
||||||
|
|
||||||
|
api.set_logger(SidecarApi::RequestLogHandler);
|
||||||
|
api.set_pre_routing_handler(
|
||||||
|
[](const auto &req, auto &res) {
|
||||||
|
for (const auto &header: req.headers) {
|
||||||
|
auto header_key = header.first;
|
||||||
|
auto header_value = header.second;
|
||||||
|
|
||||||
|
LogHTTPDetail("[API] header_key [{}] header_value [{}]", header_key, header_value);
|
||||||
|
|
||||||
|
if (header_key == "Authorization") {
|
||||||
|
std::string auth_key = header_value;
|
||||||
|
Strings::FindReplace(auth_key, "Bearer", "");
|
||||||
|
Strings::Trim(auth_key);
|
||||||
|
|
||||||
|
LogHTTPDetail(
|
||||||
|
"Request Authorization key is [{}] set key is [{}] match [{}]",
|
||||||
|
auth_key,
|
||||||
|
authorization_key,
|
||||||
|
auth_key == authorization_key ? "true" : "false"
|
||||||
|
);
|
||||||
|
|
||||||
|
// authorization key matches, pass the request on to the route handler
|
||||||
|
if (!authorization_key.empty() && auth_key != authorization_key) {
|
||||||
|
LogHTTPDetail("[Sidecar] Returning as unhandled, authorization passed");
|
||||||
|
return httplib::Server::HandlerResponse::Unhandled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!authorization_key.empty()) {
|
||||||
|
nlohmann::json j;
|
||||||
|
j["error"] = "Authorization key not valid!";
|
||||||
|
res.set_content(j.dump(), "application/json");
|
||||||
|
res.status = HTTP_RESPONSE_UNAUTHORIZED;
|
||||||
|
return httplib::Server::HandlerResponse::Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
return httplib::Server::HandlerResponse::Unhandled;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
api.Get("/api/v1/test-controller", SidecarApi::TestController);
|
||||||
|
api.Get("/api/v1/loot-simulate", SidecarApi::LootSimulatorController);
|
||||||
|
|
||||||
|
LogInfo("Webserver API now listening on port [{0}]", web_api_port);
|
||||||
|
|
||||||
|
// this is not supposed to bind to the outside world
|
||||||
|
api.listen("localhost", web_api_port);
|
||||||
|
}
|
||||||
17
zone/sidecar_api/sidecar_api.h
Normal file
17
zone/sidecar_api/sidecar_api.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#ifndef EQEMU_SIDECAR_API_H
|
||||||
|
#define EQEMU_SIDECAR_API_H
|
||||||
|
|
||||||
|
#include "../../common/http/httplib.h"
|
||||||
|
|
||||||
|
class SidecarApi {
|
||||||
|
public:
|
||||||
|
static void BootWebserver(int req = 0, const std::string& key = "");
|
||||||
|
static void AuthMiddleware(const httplib::Request &req, const httplib::Response &res);
|
||||||
|
static void RequestLogHandler(const httplib::Request &req, const httplib::Response &res);
|
||||||
|
static void TestController(const httplib::Request &req, httplib::Response &res);
|
||||||
|
static void LootSimulatorController(const httplib::Request &req, httplib::Response &res);
|
||||||
|
static void MapBestZController(const httplib::Request &req, httplib::Response &res);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //EQEMU_SIDECAR_API_H
|
||||||
10
zone/sidecar_api/test_controller.cpp
Normal file
10
zone/sidecar_api/test_controller.cpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#include "sidecar_api.h"
|
||||||
|
|
||||||
|
void SidecarApi::TestController(const httplib::Request &req, httplib::Response &res)
|
||||||
|
{
|
||||||
|
nlohmann::json j;
|
||||||
|
|
||||||
|
j["data"]["test"] = "test";
|
||||||
|
|
||||||
|
res.set_content(j.dump(), "application/json");
|
||||||
|
}
|
||||||
@ -1821,6 +1821,11 @@ void Zone::ResetShutdownTimer() {
|
|||||||
autoshutdown_timer.Start(autoshutdown_timer.GetDuration(), true);
|
autoshutdown_timer.Start(autoshutdown_timer.GetDuration(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Zone::StopShutdownTimer() {
|
||||||
|
LogInfo("Stopping zone shutdown timer");
|
||||||
|
autoshutdown_timer.Disable();
|
||||||
|
}
|
||||||
|
|
||||||
bool Zone::Depop(bool StartSpawnTimer) {
|
bool Zone::Depop(bool StartSpawnTimer) {
|
||||||
std::map<uint32,NPCType *>::iterator itr;
|
std::map<uint32,NPCType *>::iterator itr;
|
||||||
entity_list.Depop(StartSpawnTimer);
|
entity_list.Depop(StartSpawnTimer);
|
||||||
|
|||||||
@ -302,6 +302,7 @@ public:
|
|||||||
void SpawnConditionChanged(const SpawnCondition &c, int16 old_value);
|
void SpawnConditionChanged(const SpawnCondition &c, int16 old_value);
|
||||||
void StartShutdownTimer(uint32 set_time = (RuleI(Zone, AutoShutdownDelay)));
|
void StartShutdownTimer(uint32 set_time = (RuleI(Zone, AutoShutdownDelay)));
|
||||||
void ResetShutdownTimer();
|
void ResetShutdownTimer();
|
||||||
|
void StopShutdownTimer();
|
||||||
void UpdateQGlobal(uint32 qid, QGlobal newGlobal);
|
void UpdateQGlobal(uint32 qid, QGlobal newGlobal);
|
||||||
void weatherSend(Client *client = nullptr);
|
void weatherSend(Client *client = nullptr);
|
||||||
void ClearSpawnTimers();
|
void ClearSpawnTimers();
|
||||||
|
|||||||
32
zone/zone_cli.cpp
Normal file
32
zone/zone_cli.cpp
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#include "zone_cli.h"
|
||||||
|
#include "../common/cli/eqemu_command_handler.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
bool ZoneCLI::RanConsoleCommand(int argc, char **argv)
|
||||||
|
{
|
||||||
|
return argc > 1 && (strstr(argv[1], ":") != nullptr || strstr(argv[1], "--") != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZoneCLI::RanSidecarCommand(int argc, char **argv)
|
||||||
|
{
|
||||||
|
return argc > 1 && (strstr(argv[1], "sidecar:") != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneCLI::CommandHandler(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if (argc == 1) { return; }
|
||||||
|
|
||||||
|
argh::parser cmd;
|
||||||
|
cmd.parse(argc, argv, argh::parser::PREFER_PARAM_FOR_UNREG_OPTION);
|
||||||
|
EQEmuCommand::DisplayDebug(cmd);
|
||||||
|
|
||||||
|
// Declare command mapping
|
||||||
|
auto function_map = EQEmuCommand::function_map;
|
||||||
|
|
||||||
|
// Register commands
|
||||||
|
function_map["sidecar:serve-http"] = &ZoneCLI::SidecarServeHttp;
|
||||||
|
|
||||||
|
EQEmuCommand::HandleMenu(function_map, cmd, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "cli/sidecar_serve_http.cpp"
|
||||||
15
zone/zone_cli.h
Normal file
15
zone/zone_cli.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef EQEMU_ZONE_CLI_H
|
||||||
|
#define EQEMU_ZONE_CLI_H
|
||||||
|
|
||||||
|
#include "../common/cli/argh.h"
|
||||||
|
|
||||||
|
class ZoneCLI {
|
||||||
|
public:
|
||||||
|
static void CommandHandler(int argc, char **argv);
|
||||||
|
static void SidecarServeHttp(int argc, char **argv, argh::parser &cmd, std::string &description);
|
||||||
|
static bool RanConsoleCommand(int argc, char **argv);
|
||||||
|
static bool RanSidecarCommand(int argc, char **argv);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif //EQEMU_ZONE_CLI_H
|
||||||
Loading…
x
Reference in New Issue
Block a user