Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gothic 1 Support #7

Merged
merged 2 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

include(FetchContent)
set(GOTHIC_API_G1 OFF)
set(GOTHIC_API_G1 ON)
set(GOTHIC_API_G1A OFF)
set(GOTHIC_API_G2 OFF)
set(GOTHIC_API_G2A ON)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ based on the solution form [AFSP Trialogue package](https://github.com/Bad-Scien
- [x] Implement the basic functionality of the multilogue system
- [ ] Increase the default display dialogue distance if needed
- [ ] Custom camera system
- [ ] Gothic 1 compatibility
- [x] Gothic 1 compatibility

## Usage
1. Download `zMultilogue.vdf` and place it inside `<GOTHIC_ROOT>/Data` with Union installed to automatically load the plugin at the start of the game.
Expand Down
4 changes: 3 additions & 1 deletion src/Gothic/Hooks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ namespace GOTHIC_NAMESPACE {
// return (this->*Ivk_oCNpc_ActivateDialogCam)(p1);
// }

auto Ivk_oCNpc_EV_Exchange = Union::CreateHook(reinterpret_cast<void*>(0x00753E30), &oCNpc::EV_Exchange_Hook);
// G1: 0x006AE310 protected: int __thiscall oCNpc::EV_Exchange(class oCMsgManipulate *)
// G2A: 0x00753E30 protected: int __thiscall oCNpc::EV_Exchange(class oCMsgManipulate *)
auto Ivk_oCNpc_EV_Exchange = Union::CreateHook(reinterpret_cast<void*>(zSwitch(0x006AE310, 0x00753E30)), &oCNpc::EV_Exchange_Hook);
int oCNpc::EV_Exchange_Hook( oCMsgManipulate* msg ) {
zSTRING msgSlot = msg->slot;
if (msgSlot) {
Expand Down
8 changes: 8 additions & 0 deletions src/NH/Commons.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

#include <Union/String.h>

namespace NH
{
using String = Union::StringUTF8;
}
130 changes: 74 additions & 56 deletions src/NH/Logger.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,98 +4,116 @@

#include <utility>

namespace NH {
String LoggerLevelToString(LoggerLevel level) {
String values[] = {
"NONE",
"FATAL",
"ERROR",
"WARN",
"INFO",
"DEBUG",
"TRACE"
};
return values[(size_t) level];
}

LoggerLevel StringToLoggerLevel(String level) {
String values[] = {
"NONE",
"FATAL",
"ERROR",
"WARN",
"INFO",
"DEBUG",
"TRACE"
};
namespace NH
{
LoggerLevel StringToLoggerLevel(String level)
{
String values[] = { "NONE", "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" };
size_t count = sizeof(values) / sizeof(String);
for (size_t i = 0; i < count; i++) {
if (level.MakeUpper() == values[i]) {
return (LoggerLevel) i;
for (size_t i = 0; i < count; i++)
{
if (level.MakeUpper() == values[i])
{
return (LoggerLevel)i;
}
}
return LoggerLevel::None;
}

void Logger::Message(LoggerLevel level, const String &message) {
if (level == LoggerLevel::None) {
void Logger::Message(LoggerLevel level, const String& message)
{
if (level == LoggerLevel::None)
{
return;
}

size_t count = m_Adapters.GetCount();
for (size_t i = 0; i < count; i++) {
ILoggerAdapter *adapter = m_Adapters[i];
if (adapter->CanLog(level)) {
for (size_t i = 0; i < count; i++)
{
ILoggerAdapter* adapter = m_Adapters[i];
if (adapter->CanLog(level))
{
adapter->Message(level, m_LoggerName, message);
}
}
}

UnionConsoleLoggerAdapter::UnionConsoleLoggerAdapter(LoggerLevel level) : ILoggerAdapter(level) {
SetLevelColor(LoggerLevel::Fatal, Color{"\x1B[31m", "\x1B[41;1m\x1B[37;1m", "\x1B[41m\x1B[37;1m"});
SetLevelColor(LoggerLevel::Error, Color{"\x1B[31m", "\x1B[41;1m\x1B[37;1m", "\x1B[31;1m"});
SetLevelColor(LoggerLevel::Warn, Color{"\x1B[33m", "\x1B[43;1m\x1B[37m", "\x1B[0m\x1B[33;1m"});
SetLevelColor(LoggerLevel::Info, Color{"\x1b[37m", "\x1B[47;1m\x1B[30m", "\x1B[0m"});
SetLevelColor(LoggerLevel::Debug, Color{"\x1B[32m", "\x1B[42;1m\x1B[37;1m", "\x1B[0m\x1B[32;1m"});
SetLevelColor(LoggerLevel::Trace, Color{"\x1B[30;1m", "\x1B[47;1m\x1B[30m", "\x1B[37m"});
void Logger::PrintRaw(LoggerLevel level, const String& message) const
{
auto* adapter = GetAdapter<UnionConsoleLoggerAdapter>();
if ((adapter && adapter->CanLog(level)) || !adapter)
{
String::Format("\x1B[0m\x1B[36;3m{0}\x1B[0m", message).StdPrintLine();
}
}

UnionConsoleLoggerAdapter::UnionConsoleLoggerAdapter(LoggerLevel level) : ILoggerAdapter(level)
{
SetLevelColor(LoggerLevel::Fatal, Color{ "\x1B[31m", "\x1B[41;1m\x1B[37;1m", "\x1B[41m\x1B[37;1m" });
SetLevelColor(LoggerLevel::Error, Color{ "\x1B[31m", "\x1B[41;1m\x1B[37;1m", "\x1B[31;1m" });
SetLevelColor(LoggerLevel::Warn, Color{ "\x1B[33m", "\x1B[43;1m\x1B[37m", "\x1B[0m\x1B[33;1m" });
SetLevelColor(LoggerLevel::Info, Color{ "\x1B[36;1m", "\x1B[44m\x1B[37;1m", "\x1B[36m" });
SetLevelColor(LoggerLevel::Debug, Color{ "\x1B[32m", "\x1B[42;1m\x1B[37;1m", "\x1B[0m\x1B[32;1m" });
SetLevelColor(LoggerLevel::Trace, Color{ "\x1B[35m", "\x1B[35;1m\x1B[30m", "\x1B[35;1m" });
}

void UnionConsoleLoggerAdapter::SetLevelColor(LoggerLevel level, Color color) {
m_ColorTable[(size_t) level] = std::move(color);
void UnionConsoleLoggerAdapter::SetLevelColor(LoggerLevel level, Color color)
{
m_ColorTable[(size_t)level] = std::move(color);
}

void UnionConsoleLoggerAdapter::Message(LoggerLevel level, const String &channel, const String &message) {
Color color = m_ColorTable[(size_t) level];
void UnionConsoleLoggerAdapter::Message(LoggerLevel level, const String& channel, const String& message)
{
Color color = m_ColorTable[(size_t)level];

String::Format("\x1B[0m{0} {1} \x1B[0m {2}[{3}]\x1B[0m {4}{5}\x1B[0m",
color.Level, LoggerLevelToString(level),
color.Level, LoggerLevelToDisplayString(level),
color.Channel, channel,
color.Message, message)
.StdPrintLine();
}

void ZSpyLoggerAdapter::Message(LoggerLevel level, const String &channel, const String &message) {
void ZSpyLoggerAdapter::Message(LoggerLevel level, const String& channel, const String& message)
{
String formattedMessage = String(m_Prefix) + ":\t" + channel + ": [" + LoggerLevelToString(level) + "]" + message;

switch (GetGameVersion()) {
case Engine_G2A:
Gothic_II_Addon::zerr->Message(Gothic_II_Addon::zSTRING(formattedMessage.ToChar()));
break;
switch (GetGameVersion())
{
case Engine_G1:
Gothic_I_Classic::zerr->Message(Gothic_I_Classic::zSTRING(formattedMessage.ToChar()));
break;
case Engine_G2A:
Gothic_II_Addon::zerr->Message(Gothic_II_Addon::zSTRING(formattedMessage.ToChar()));
break;
}
}

LoggerFactory *LoggerFactory::s_Instance = null;
LoggerLevel UnionConsoleLoggerAdapter::DEFAULT_LEVEL = LoggerLevel::Debug;
LoggerLevel ZSpyLoggerAdapter::DEFAULT_LEVEL = LoggerLevel::Debug;

LoggerFactory* LoggerFactory::s_Instance = null;

Logger* LoggerFactory::Create(const String& name)
{

for (auto* logger: m_Loggers)
{
if (logger->m_LoggerName == name)
{
return logger;
}
}

Logger *LoggerFactory::Create(const String &name, LoggerLevel level) {
auto *logger = new NH::Logger(name, {
new NH::UnionConsoleLoggerAdapter(level),
new NH::ZSpyLoggerAdapter(level, "E")
auto* logger = new NH::Logger(name, {
new NH::UnionConsoleLoggerAdapter(UnionConsoleLoggerAdapter::DEFAULT_LEVEL),
new NH::ZSpyLoggerAdapter(ZSpyLoggerAdapter::DEFAULT_LEVEL, "B")
});
m_Loggers.Insert(logger);
return logger;
}

Logger *CreateLogger(const String &name) {
return LoggerFactory::GetInstance()->Create(name, LoggerLevel::Trace);
Logger* CreateLogger(const String& name)
{
return LoggerFactory::GetInstance()->Create(name);
}
}
35 changes: 23 additions & 12 deletions src/NH/Logger.h
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#pragma once

#include <NH/Commons.h>
#include <Union/String.h>
#include <Union/Array.h>

namespace NH
{
using String = Union::StringUTF8;

enum class LoggerLevel : size_t
{
Expand All @@ -18,7 +18,17 @@ namespace NH
Trace = 6
};

String LoggerLevelToString(LoggerLevel level);
constexpr const char* LoggerLevelToString(LoggerLevel level)
{
constexpr const char* values[] = { "NONE", "FATAL", "ERROR", "WARN", "INFO", "DEBUG", "TRACE" };
return values[(size_t)level];
}

constexpr const char* LoggerLevelToDisplayString(LoggerLevel level)
{
constexpr const char* values[] = { " NONE", "FATAL", "ERROR", " WARN", " INFO", "DEBUG", "TRACE" };
return values[(size_t)level];
}

LoggerLevel StringToLoggerLevel(String level);

Expand All @@ -32,6 +42,7 @@ namespace NH
LoggerLevel m_Level;

explicit ILoggerAdapter(LoggerLevel level = LoggerLevel::Debug) : m_Level(level) {}
virtual ~ILoggerAdapter() = default;

bool CanLog(LoggerLevel level) const { return level <= m_Level; }

Expand All @@ -48,12 +59,16 @@ namespace NH
Union::Array<ILoggerAdapter*> m_Adapters;

public:
friend class LoggerFactory;

explicit Logger(const String& name) : m_LoggerName(name) {};

explicit Logger(const String& name, Union::Array<ILoggerAdapter*> adapters) : m_LoggerName(name), m_Adapters(adapters) {};

void Message(LoggerLevel level, const String& message);

void PrintRaw(LoggerLevel level, const String& message) const;

template<typename... Args>
void Message(LoggerLevel level, const char* format, Args... args) { Message(level, String::Format(format, args...)); }

Expand Down Expand Up @@ -87,17 +102,9 @@ namespace NH
template<typename... Args>
void Trace(const char* format, Args... args) { Trace(String::Format(format, args...)); }

void SetLoggerLevel(LoggerLevel level)
{
for (size_t i = 0; i < m_Adapters.GetCount(); i++)
{
m_Adapters[i]->SetLoggerLevel(level);
}
}

Union::Array<ILoggerAdapter*> GetAdapters() const { return m_Adapters; };

template <class T>
template<class T>
T* GetAdapter() const
{
for (int i = 0; i < m_Adapters.GetCount(); i++)
Expand All @@ -116,6 +123,8 @@ namespace NH
class UnionConsoleLoggerAdapter : public ILoggerAdapter
{
public:
static LoggerLevel DEFAULT_LEVEL;

struct Color
{
String Channel;
Expand All @@ -140,6 +149,8 @@ namespace NH
String m_Prefix;

public:
static LoggerLevel DEFAULT_LEVEL;

explicit ZSpyLoggerAdapter(LoggerLevel level = LoggerLevel::Debug, const String& prefix = "N") : ILoggerAdapter(level), m_Prefix(prefix) {}

protected:
Expand All @@ -155,7 +166,7 @@ namespace NH
LoggerFactory() = default;

public:
Logger* Create(const String& name, LoggerLevel level = LoggerLevel::Trace);
Logger* Create(const String& name);

Union::Array<Logger*> GetLoggers() { return m_Loggers.Share(); };

Expand Down
13 changes: 13 additions & 0 deletions src/Plugin.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,21 @@
// Disable macro redefinition warning
#pragma warning(disable: 4005)

#include <Union/Hook.h>
#include <ZenGin/zGothicAPI.h>

#include "NH/Logger.h"


#ifdef __G1
#define GOTHIC_NAMESPACE Gothic_I_Classic
#define ENGINE Engine_G1
HOOKSPACE(Gothic_I_Classic, GetGameVersion() == ENGINE);

#include "Plugin.hpp"

#endif

#ifdef __G2A
#define GOTHIC_NAMESPACE Gothic_II_Addon
#define ENGINE Engine_G2A
Expand Down
2 changes: 1 addition & 1 deletion userapi/oCNpc.inl
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
// User API for oCNpc
// Add your methods here

int ActivateDialogCam_Hook(float);
// int ActivateDialogCam_Hook(float);
int EV_Exchange_Hook(oCMsgManipulate*);