Compare commits

...

3 Commits

  1. 15
      CMakeLists.txt
  2. 36
      README.md
  3. 38
      src/Bot/src/Main.cpp
  4. 3
      src/CMakeLists.txt
  5. 2
      src/Jupiter
  6. 8
      src/Plugins/RenX/RenX.Commands/RenX_Commands.cpp
  7. 6
      src/Plugins/RenX/RenX.Core/RenX_BanDatabase.cpp
  8. 11
      src/Plugins/RenX/RenX.Core/RenX_LadderDatabase.cpp

15
CMakeLists.txt

@ -125,18 +125,17 @@ add_custom_command(TARGET PackagedBuild
########################## ##########################
if (INSTALL_JUPITER_BOT) if (INSTALL_JUPITER_BOT)
message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") message(STATUS "CMAKE_INSTALL_PREFIX: ${CMAKE_INSTALL_PREFIX}") # Prefixed onto all of the below by CMake before use
message(STATUS "CMAKE_INSTALL_BINDIR: ${CMAKE_INSTALL_BINDIR}") message(STATUS "CMAKE_INSTALL_BINDIR: ${CMAKE_INSTALL_BINDIR}") # bin; Used for executable files (jupiter_bot) & .dll libraries
message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}") message(STATUS "CMAKE_INSTALL_LIBDIR: ${CMAKE_INSTALL_LIBDIR}") # lib; Used for .so libraries
message(STATUS "CMAKE_INSTALL_INCLUDEDIR: ${CMAKE_INSTALL_INCLUDEDIR}") message(STATUS "CMAKE_INSTALL_INCLUDEDIR: ${CMAKE_INSTALL_INCLUDEDIR}") # include; Not used yet
message(STATUS "CMAKE_INSTALL_SYSCONFDIR: ${CMAKE_INSTALL_SYSCONFDIR}") message(STATUS "CMAKE_INSTALL_SYSCONFDIR: ${CMAKE_INSTALL_SYSCONFDIR}") # etc; Used for baselines (configs)
message(STATUS "CMAKE_INSTALL_LOCALSTATEDIR: ${CMAKE_INSTALL_LOCALSTATEDIR}") message(STATUS "CMAKE_INSTALL_LOCALSTATEDIR: ${CMAKE_INSTALL_LOCALSTATEDIR}") # var; Not used (yet?)
message(STATUS "CMAKE_INSTALL_DATADIR: ${CMAKE_INSTALL_DATADIR}") message(STATUS "CMAKE_INSTALL_DATADIR: ${CMAKE_INSTALL_DATADIR}") # blank; Not used (yet?)
set(JUPITER_BOT_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}") set(JUPITER_BOT_INSTALL_BINDIR "${CMAKE_INSTALL_BINDIR}")
set(JUPITER_BOT_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}") set(JUPITER_BOT_INSTALL_LIBDIR "${CMAKE_INSTALL_LIBDIR}")
set(JUPITER_BOT_INSTALL_SYSCONFDIR "${CMAKE_INSTALL_SYSCONFDIR}") set(JUPITER_BOT_INSTALL_SYSCONFDIR "${CMAKE_INSTALL_SYSCONFDIR}")
set(JUPITER_BOT_INSTALL_DATADIR "${CMAKE_INSTALL_DATADIR}")
# Jupiter Bot program binary # Jupiter Bot program binary
set(JUPITER_BOT_INSTALL_EXE "jupiter_bot${CMAKE_EXECUTABLE_SUFFIX}") set(JUPITER_BOT_INSTALL_EXE "jupiter_bot${CMAKE_EXECUTABLE_SUFFIX}")

36
README.md

@ -1,17 +1,27 @@
[![CMake](https://github.com/JAJames/Jupiter-Bot/actions/workflows/cmake.yml/badge.svg)](https://github.com/JAJames/Jupiter-Bot/actions/workflows/cmake.yml) [![CMake](https://github.com/JAJames/Jupiter-Bot/actions/workflows/cmake.yml/badge.svg)](https://github.com/JAJames/Jupiter-Bot/actions/workflows/cmake.yml)
Original ReadMe.txt, needs to be updated: ## Configuration
``` There are also many configuration options in the Config files. Please read through these to get an idea of what
The command line for this application is as follows: exactly you can actually configure the bot to do. Typically only one instance of the bot is needed, regardless of
Bot.exe [-config Config.ini] [-pluginsdir Plugins\] the number of game servers, as long as they will be configured similarly.
There are also many configuration options in the Config Some INI files, particularly RenX.Medals.ini, RenX.ModSystem.ini, SetJoin.ini, and RenX.SetJoin.ini, may be overwritten
file. Please read through these to get an idea of what at runtime. All comments in the file will be lost when this occurs. These will be changed to not be overwritten in the
exactly you can actually configure the bot to do. If you future.
understand how to configure this bot, you can potentially
reduce all of your IRC bots down to a single instance.
Also: Take note that whenever the bot syncs the config ## Command Line
from memory to the file (such as when adding a setjoin), All examples prefix arguments with `--`, however the bot also accepts arguments prefixed with `-`, and will accept
all comments in the file are destroyed. either `=` or a space (` `) for argument values. All parameters are optional, and all switches are unset by default.
``` ### Syntax
`Bot.exe [--config=Config.ini] [--pluginsdir=Plugins\] [--configsdir=Configs\] [--echo-parameters] [--exit]`
### Options
* `--config`: Specifies the path to the application config file.
* `--pluginsdir`: Specifies the path to the Plugins directory (where the .so or .dll files are).
* `--configsdir`: Specifies the path to the Configs directory (where the .ini files, other than main config, are)
* `--echo-parameters`: Echos the parameters on the command-line back to the user (useful for script debugging)
* `--exit`: Immediately exits the application post-initialization (useful for startup crash testing).
## Commands
The commands available depend on where commands are being invoked, the invoking user's access level, and the plugins
loaded. To get a full list of available commands, setup the bot and execute the help command (`!help`). The help command
also provides command-specific help messages explaining what each command does and its syntax.

38
src/Bot/src/Main.cpp

@ -31,6 +31,7 @@
#include "Jupiter/Plugin.h" #include "Jupiter/Plugin.h"
#include "Jupiter/Timer.h" #include "Jupiter/Timer.h"
#include "jessilib/word_split.hpp" #include "jessilib/word_split.hpp"
#include "jessilib/serialize.hpp"
#include "IRC_Bot.h" #include "IRC_Bot.h"
#include "Console_Command.h" #include "Console_Command.h"
#include "IRC_Command.h" #include "IRC_Command.h"
@ -58,13 +59,13 @@ struct ConsoleInput {
} console_input; } console_input;
void onTerminate() { void onTerminate() {
puts("Terminate signal received..."); std::cout << "Terminate signal received..." << std::endl;
} }
void onExit() { void onExit() {
puts("Exit signal received; Cleaning up..."); std::cout << "Exit signal received; Cleaning up..." << std::endl;
Jupiter::Socket::cleanup(); Jupiter::Socket::cleanup();
puts("Clean-up complete. Closing..."); std::cout << "Clean-up complete. Closing..." << std::endl;
} }
void inputLoop() { void inputLoop() {
@ -155,7 +156,7 @@ void reinitialize_plugins() {
command->trigger(input_split.second); command->trigger(input_split.second);
} }
else { else {
printf("Error: Command \"%.*s\" not found." ENDL, static_cast<int>(command_name.size()), command_name.data()); std::cout << "Error: Command \"" << command_name << "\" not found." << std::endl;
} }
} }
console_input.input_mutex.unlock(); console_input.input_mutex.unlock();
@ -188,6 +189,14 @@ int main(int argc, char* argv[]) {
return 0; return 0;
} }
if (parameters.has_switch(u8"echo-parameters")) {
// TODO: Write pretty JSON serializer based on JSON serializer
// TODO: add a format specifier parameter
std::cout << "Echoing app_parameters: " << std::endl
<< jessilib::ustring_to_mbstring(jessilib::serialize_object(parameters, "json")).second << std::endl
<< std::endl; // leave an extra empty line so it's easier to read or copy/paste
}
std::string_view configFileName = jessilib::string_view_cast<char>(parameters.get_value(u8"config", u8"Config.ini"sv)); std::string_view configFileName = jessilib::string_view_cast<char>(parameters.get_value(u8"config", u8"Config.ini"sv));
std::string_view plugins_directory = jessilib::string_view_cast<char>(parameters.get_value(u8"pluginsdir"sv)); std::string_view plugins_directory = jessilib::string_view_cast<char>(parameters.get_value(u8"pluginsdir"sv));
std::string_view configs_directory = jessilib::string_view_cast<char>(parameters.get_value(u8"configsdir"sv)); std::string_view configs_directory = jessilib::string_view_cast<char>(parameters.get_value(u8"configsdir"sv));
@ -202,7 +211,7 @@ int main(int argc, char* argv[]) {
double time_taken = static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - load_start).count()) / 1000.0; double time_taken = static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - load_start).count()) / 1000.0;
printf("Config loaded (%fms)." ENDL, time_taken); std::cout << "Config loaded (" << time_taken << "ms)." << std::endl;
if (plugins_directory.empty()) if (plugins_directory.empty())
plugins_directory = o_config.get("PluginsDirectory"sv); plugins_directory = o_config.get("PluginsDirectory"sv);
@ -212,23 +221,32 @@ int main(int argc, char* argv[]) {
if (!plugins_directory.empty()) { if (!plugins_directory.empty()) {
Jupiter::Plugin::setDirectory(plugins_directory); Jupiter::Plugin::setDirectory(plugins_directory);
printf("Plugins will be loaded from \"%.*s\"." ENDL, static_cast<int>(plugins_directory.size()), plugins_directory.data()); std::cout << "Plugins will be loaded from \"" << plugins_directory << "\"." << std::endl;
} }
if (!configs_directory.empty()) { if (!configs_directory.empty()) {
Jupiter::Plugin::setConfigDirectory(configs_directory); Jupiter::Plugin::setConfigDirectory(configs_directory);
printf("Plugin configs will be loaded from \"%.*s\"." ENDL, static_cast<int>(configs_directory.size()), configs_directory.data()); std::cout << "Plugin configs will be loaded from \"" << configs_directory << "\"." << std::endl;
} }
initialize_plugins(); initialize_plugins();
printf("Initialization completed in %f milliseconds." ENDL, static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - Jupiter::g_start_time).count()) / 1000.0 ); time_taken = static_cast<double>(std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - Jupiter::g_start_time).count()) / 1000.0;
std::cout << "Initialization completed in " << time_taken << " milliseconds." << std::endl;
if (!consoleCommands.empty()) { if (!consoleCommands.empty()) {
printf("%zu Console Commands have been initialized%s" ENDL, consoleCommands.size(), getConsoleCommand("help"sv) == nullptr ? "." : "; type \"help\" for more information."); std::cout << consoleCommands.size() << " Console Commands have been initialized"
<< (getConsoleCommand("help"sv) == nullptr ? "." : "; type \"help\" for more information.")
<< std::endl;
} }
if (!IRCMasterCommandList.empty()) { if (!IRCMasterCommandList.empty()) {
printf("%zu IRC Commands have been loaded into the master list." ENDL, IRCMasterCommandList.size()); std::cout << IRCMasterCommandList.size() << " IRC Commands have been loaded into the master list." << std::endl;
}
if (parameters.has_switch(u8"exit")) {
std::cout << "exit switch specified; closing down post-initialization before entering main_loop" << std::endl;
return 0;
} }
main_loop(); main_loop();

3
src/CMakeLists.txt

@ -9,6 +9,9 @@ set(CMAKE_SHARED_LIBRARY_PREFIX)
set(BUILD_SHARED_LIBS ON) set(BUILD_SHARED_LIBS ON)
set(INSTALL_GTEST OFF) set(INSTALL_GTEST OFF)
# Jupiter Bot cannot yet survive without JESSILIB_CHAR_AS_UTF8
add_compile_definitions(JESSILIB_CHAR_AS_UTF8)
# Add primary components (Jupiter, Bot) # Add primary components (Jupiter, Bot)
add_subdirectory(Jupiter) add_subdirectory(Jupiter)
add_subdirectory(Bot) add_subdirectory(Bot)

2
src/Jupiter

@ -1 +1 @@
Subproject commit 9284c2b23ba25c57131b14b22bc3f49f1c926b35 Subproject commit 4ce0bfba50c88f603769b11e8a44023469c95047

8
src/Plugins/RenX/RenX.Commands/RenX_Commands.cpp

@ -132,13 +132,13 @@ RawRCONConsoleCommand::RawRCONConsoleCommand() {
void RawRCONConsoleCommand::trigger(std::string_view parameters) { void RawRCONConsoleCommand::trigger(std::string_view parameters) {
if (parameters.empty()) { if (parameters.empty()) {
puts("Error: Too Few Parameters. Syntax: rrcon <input>"); std::cout << "Error: Too Few Parameters. Syntax: rrcon <input>" << std::endl;
return; return;
} }
const auto& servers = RenX::getCore()->getServers(); const auto& servers = RenX::getCore()->getServers();
if (servers.empty()) { if (servers.empty()) {
puts("Error: Not connected to any Renegade X servers."); std::cout << "Error: Not connected to any Renegade X servers." << std::endl;
return; return;
} }
@ -165,12 +165,12 @@ RCONConsoleCommand::RCONConsoleCommand() {
void RCONConsoleCommand::trigger(std::string_view parameters) { void RCONConsoleCommand::trigger(std::string_view parameters) {
if (parameters.empty()) { if (parameters.empty()) {
puts("Error: Too Few Parameters. Syntax: rcon <input>"); std::cout << "Error: Too Few Parameters. Syntax: rcon <input>" << std::endl;
} }
const auto& servers = RenX::getCore()->getServers(); const auto& servers = RenX::getCore()->getServers();
if (servers.empty()) { if (servers.empty()) {
puts("Error: Not connected to any Renegade X servers."); std::cout << "Error: Not connected to any Renegade X servers." << std::endl;
return; return;
} }

6
src/Plugins/RenX/RenX.Core/RenX_BanDatabase.cpp

@ -17,7 +17,7 @@
*/ */
#include <ctime> #include <ctime>
#include <cstdio> #include <iostream>
#include "Jupiter/IRC_Client.h" #include "Jupiter/IRC_Client.h"
#include "Jupiter/DataBuffer.h" #include "Jupiter/DataBuffer.h"
#include "RenX_PlayerInfo.h" #include "RenX_PlayerInfo.h"
@ -84,11 +84,11 @@ void RenX::BanDatabase::create_header(FILE *file)
void RenX::BanDatabase::process_file_finish(FILE *file) { void RenX::BanDatabase::process_file_finish(FILE *file) {
if (m_read_version < 3) { if (m_read_version < 3) {
if (freopen(m_filename.c_str(), "wb", file) == nullptr) { if (freopen(m_filename.c_str(), "wb", file) == nullptr) {
puts("FATAL ERROR: UNABLE TO REMOVE UNSUPPORTED BAN DATABASE FILE VERSION"); std::cout << "FATAL ERROR: UNABLE TO REMOVE UNSUPPORTED BAN DATABASE FILE VERSION" << std::endl;
return; return;
} }
puts("Warning: Unsupported ban database file version. The database will be removed and rewritten."); std::cout << "Warning: Unsupported ban database file version. The database will be removed and rewritten." << std::endl;
create_header(file); create_header(file);
fgetpos(file, std::addressof(m_eof)); fgetpos(file, std::addressof(m_eof));
m_read_version = m_write_version; m_read_version = m_write_version;

11
src/Plugins/RenX/RenX.Core/RenX_LadderDatabase.cpp

@ -175,14 +175,15 @@ void RenX::LadderDatabase::create_header(FILE *file) {
void RenX::LadderDatabase::process_file_finish(FILE *file) { void RenX::LadderDatabase::process_file_finish(FILE *file) {
if (m_read_version != m_write_version) { if (m_read_version != m_write_version) {
puts("Notice: Ladder database is out of date; upgrading..."); std::cout << "Notice: Ladder database is out of date; upgrading..." << std::endl;
std::chrono::steady_clock::duration write_duration;
std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now();
std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now();
write(this->getFilename()); write(this->getFilename());
std::chrono::steady_clock::duration write_duration = std::chrono::steady_clock::now() - start_time;
write_duration = std::chrono::steady_clock::now() - start_time; // This does not seem anything close to correct...
printf("Ladder database upgrade completed in %f seconds", static_cast<double>(write_duration.count()) * (static_cast<double>(std::chrono::steady_clock::duration::period::num) / static_cast<double>(std::chrono::steady_clock::duration::period::den) * static_cast<double>(std::chrono::seconds::duration::period::den / std::chrono::seconds::duration::period::num))); double time_taken = static_cast<double>(write_duration.count()) * (static_cast<double>(std::chrono::steady_clock::duration::period::num) / static_cast<double>(std::chrono::steady_clock::duration::period::den) * static_cast<double>(std::chrono::seconds::duration::period::den / std::chrono::seconds::duration::period::num));
std::cout << "Ladder database upgrade completed in " << time_taken << " seconds" << std::endl;
m_read_version = m_write_version; m_read_version = m_write_version;
} }
} }

Loading…
Cancel
Save