mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-07-13 19:01:56 +00:00
Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1dbaf6a2bc | ||
|
|
4860410f6f | ||
|
|
0b261e934f | ||
|
|
701fc8061b | ||
|
|
6699081080 | ||
|
|
4922e2edb1 | ||
|
|
c05c2543a9 | ||
|
|
5599bd946b | ||
|
|
a568e66e41 | ||
|
|
66fa3ff4ba | ||
|
|
6fa719c679 | ||
|
|
7740bbbaab | ||
|
|
8eb3488812 | ||
|
|
ac4fd02a6c | ||
|
|
b799f8967c | ||
|
|
12387ba07d | ||
|
|
051a0ba05e | ||
|
|
5aa8b1395b | ||
|
|
3a0e37ee8a | ||
|
|
0a06f309f6 | ||
|
|
30d4076808 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -2,6 +2,7 @@ temp/
|
|||||||
cmake-build-debug/
|
cmake-build-debug/
|
||||||
RelWithDebInfo/
|
RelWithDebInfo/
|
||||||
docker/configs
|
docker/configs
|
||||||
|
valgrind-out.txt
|
||||||
|
|
||||||
# Third party libraries
|
# Third party libraries
|
||||||
thirdparty/mysql/
|
thirdparty/mysql/
|
||||||
|
|||||||
@@ -4,6 +4,18 @@ project(Darkflame
|
|||||||
LANGUAGES C CXX
|
LANGUAGES C CXX
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Sanitizer flags - TODO: Make CMake preset before finalizing PR
|
||||||
|
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||||
|
add_compile_options("-fsanitize=undefined")
|
||||||
|
add_link_options("-fsanitize=undefined")
|
||||||
|
|
||||||
|
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||||
|
add_link_options("-static-libsan")
|
||||||
|
else()
|
||||||
|
add_link_options("-static-libasan")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# check if the path to the source directory contains a space
|
# check if the path to the source directory contains a space
|
||||||
if("${CMAKE_SOURCE_DIR}" MATCHES " ")
|
if("${CMAKE_SOURCE_DIR}" MATCHES " ")
|
||||||
message(FATAL_ERROR "The server cannot build in the path (" ${CMAKE_SOURCE_DIR} ") because it contains a space. Please move the server to a path without spaces.")
|
message(FATAL_ERROR "The server cannot build in the path (" ${CMAKE_SOURCE_DIR} ") because it contains a space. Please move the server to a path without spaces.")
|
||||||
@@ -17,7 +29,7 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
|
|||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Export the compile commands for debugging
|
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # Export the compile commands for debugging
|
||||||
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) # Set CMAKE visibility policy to NEW on project and subprojects
|
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW) # Set CMAKE visibility policy to NEW on project and subprojects
|
||||||
set(CMAKE_VISIBILITY_INLINES_HIDDEN ON) # Set C and C++ symbol visibility to hide inlined functions
|
set(CMAKE_VISIBILITY_INLINES_HIDDEN OFF) # Set C and C++ symbol visibility to hide inlined functions
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
# Read variables from file
|
# Read variables from file
|
||||||
@@ -262,7 +274,7 @@ if(MSVC)
|
|||||||
# add_compile_options("/W4")
|
# add_compile_options("/W4")
|
||||||
# Want to enable warnings eventually, but WAY too much noise right now
|
# Want to enable warnings eventually, but WAY too much noise right now
|
||||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang|GNU")
|
||||||
add_compile_options("-Wuninitialized" "-Wold-style-cast")
|
add_compile_options("-Wuninitialized" "-Wold-style-cast" "-Wstrict-aliasing=01")
|
||||||
else()
|
else()
|
||||||
message(WARNING "Unknown compiler: '${CMAKE_CXX_COMPILER_ID}' - No warning flags enabled.")
|
message(WARNING "Unknown compiler: '${CMAKE_CXX_COMPILER_ID}' - No warning flags enabled.")
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
# Try and find a clang-16 install, falling back to a generic clang install otherwise
|
# Try and find a clang-16 install, falling back to a generic clang install otherwise
|
||||||
find_program(CLANG_C_COMPILER clang-16 | clang REQUIRED)
|
find_program(CLANG_C_COMPILER clang-16 | clang REQUIRED)
|
||||||
find_program(CLANG_CXX_COMPILER clang++-16 | clang++ REQUIRED)
|
find_program(CLANG_CXX_COMPILER clang++-16 | clang++ REQUIRED)
|
||||||
|
find_program(CLANG_CXX_LINKER lld REQUIRED)
|
||||||
|
|
||||||
# Debug messages
|
# Debug messages
|
||||||
message(DEBUG "CLANG_C_COMPILER = ${CLANG_C_COMPILER}")
|
message(DEBUG "CLANG_C_COMPILER = ${CLANG_C_COMPILER}")
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#ifndef __AMF3__H__
|
#ifndef AMF3_H
|
||||||
#define __AMF3__H__
|
#define AMF3_H
|
||||||
|
|
||||||
#include "dCommonVars.h"
|
#include "dCommonVars.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "Game.h"
|
#include "Game.h"
|
||||||
|
#include "GeneralUtils.h"
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -74,28 +75,15 @@ template <> [[nodiscard]] constexpr eAmf AMFValue<double>::GetValueType() const
|
|||||||
template <typename ValueType>
|
template <typename ValueType>
|
||||||
[[nodiscard]] constexpr eAmf AMFValue<ValueType>::GetValueType() const noexcept { return eAmf::Undefined; }
|
[[nodiscard]] constexpr eAmf AMFValue<ValueType>::GetValueType() const noexcept { return eAmf::Undefined; }
|
||||||
|
|
||||||
// As a string this is much easier to write and read from a BitStream.
|
|
||||||
template <>
|
|
||||||
class AMFValue<const char*> : public AMFBaseValue {
|
|
||||||
public:
|
|
||||||
AMFValue() = default;
|
|
||||||
AMFValue(const char* value) { m_Data = value; }
|
|
||||||
virtual ~AMFValue() override = default;
|
|
||||||
|
|
||||||
[[nodiscard]] constexpr eAmf GetValueType() const noexcept override { return eAmf::String; }
|
|
||||||
|
|
||||||
[[nodiscard]] const std::string& GetValue() const { return m_Data; }
|
|
||||||
void SetValue(const std::string& value) { m_Data = value; }
|
|
||||||
protected:
|
|
||||||
std::string m_Data;
|
|
||||||
};
|
|
||||||
|
|
||||||
using AMFNullValue = AMFValue<std::nullptr_t>;
|
using AMFNullValue = AMFValue<std::nullptr_t>;
|
||||||
using AMFBoolValue = AMFValue<bool>;
|
using AMFBoolValue = AMFValue<bool>;
|
||||||
using AMFIntValue = AMFValue<int32_t>;
|
using AMFIntValue = AMFValue<int32_t>;
|
||||||
using AMFStringValue = AMFValue<std::string>;
|
using AMFStringValue = AMFValue<std::string>;
|
||||||
using AMFDoubleValue = AMFValue<double>;
|
using AMFDoubleValue = AMFValue<double>;
|
||||||
|
|
||||||
|
// Template deduction guide to ensure string literals deduce
|
||||||
|
AMFValue(const char*) -> AMFValue<std::string>; // AMFStringValue
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The AMFArrayValue object holds 2 types of lists:
|
* The AMFArrayValue object holds 2 types of lists:
|
||||||
* An associative list where a key maps to a value
|
* An associative list where a key maps to a value
|
||||||
@@ -106,7 +94,7 @@ using AMFDoubleValue = AMFValue<double>;
|
|||||||
*/
|
*/
|
||||||
class AMFArrayValue : public AMFBaseValue {
|
class AMFArrayValue : public AMFBaseValue {
|
||||||
using AMFAssociative =
|
using AMFAssociative =
|
||||||
std::unordered_map<std::string, std::unique_ptr<AMFBaseValue>, GeneralUtils::transparent_string_hash, std::equal_to<>>;
|
std::unordered_map<std::string, std::unique_ptr<AMFBaseValue>, GeneralUtils::transparent_string_hash, std::equal_to<void>>;
|
||||||
|
|
||||||
using AMFDense = std::vector<std::unique_ptr<AMFBaseValue>>;
|
using AMFDense = std::vector<std::unique_ptr<AMFBaseValue>>;
|
||||||
|
|
||||||
@@ -137,17 +125,20 @@ public:
|
|||||||
* @return The inserted element if the type matched,
|
* @return The inserted element if the type matched,
|
||||||
* or nullptr if a key existed and was not the same type
|
* or nullptr if a key existed and was not the same type
|
||||||
*/
|
*/
|
||||||
template <typename ValueType>
|
template <typename T>
|
||||||
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const std::string_view key, const ValueType value) {
|
[[maybe_unused]] auto Insert(const std::string_view key, const T value) -> std::pair<decltype(AMFValue(value))*, bool> {
|
||||||
|
// This ensures the deduced type matches the AMFValue constructor
|
||||||
|
using AMFValueType = decltype(AMFValue(value));
|
||||||
|
|
||||||
const auto element = m_Associative.find(key);
|
const auto element = m_Associative.find(key);
|
||||||
AMFValue<ValueType>* val = nullptr;
|
AMFValueType* val = nullptr;
|
||||||
bool found = true;
|
bool found = true;
|
||||||
if (element == m_Associative.cend()) {
|
if (element == m_Associative.cend()) {
|
||||||
auto newVal = std::make_unique<AMFValue<ValueType>>(value);
|
auto newVal = std::make_unique<AMFValueType>(value);
|
||||||
val = newVal.get();
|
val = newVal.get();
|
||||||
m_Associative.emplace(key, std::move(newVal));
|
m_Associative.emplace(key, std::move(newVal));
|
||||||
} else {
|
} else {
|
||||||
val = dynamic_cast<AMFValue<ValueType>*>(element->second.get());
|
val = dynamic_cast<AMFValueType*>(element->second.get());
|
||||||
found = false;
|
found = false;
|
||||||
}
|
}
|
||||||
return std::make_pair(val, found);
|
return std::make_pair(val, found);
|
||||||
@@ -190,15 +181,18 @@ public:
|
|||||||
* @return The inserted element, or nullptr if the type did not match
|
* @return The inserted element, or nullptr if the type did not match
|
||||||
* what was at the index.
|
* what was at the index.
|
||||||
*/
|
*/
|
||||||
template <typename ValueType>
|
template <typename T>
|
||||||
[[maybe_unused]] std::pair<AMFValue<ValueType>*, bool> Insert(const size_t index, const ValueType value) {
|
[[maybe_unused]] auto Insert(const size_t index, const T value) -> std::pair<decltype(AMFValue(value))*, bool> {
|
||||||
|
// This ensures the deduced type matches the AMFValue constructor
|
||||||
|
using AMFValueType = decltype(AMFValue(value));
|
||||||
|
|
||||||
bool inserted = false;
|
bool inserted = false;
|
||||||
if (index >= m_Dense.size()) {
|
if (index >= m_Dense.size()) {
|
||||||
m_Dense.resize(index + 1);
|
m_Dense.resize(index + 1);
|
||||||
m_Dense.at(index) = std::make_unique<AMFValue<ValueType>>(value);
|
m_Dense.at(index) = std::make_unique<AMFValueType>(value);
|
||||||
inserted = true;
|
inserted = true;
|
||||||
}
|
}
|
||||||
return std::make_pair(dynamic_cast<AMFValue<ValueType>*>(m_Dense.at(index).get()), inserted);
|
return std::make_pair(dynamic_cast<AMFValueType*>(m_Dense.at(index).get()), inserted);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -245,8 +239,8 @@ public:
|
|||||||
*
|
*
|
||||||
* @return The inserted pointer, or nullptr should the key already be in use.
|
* @return The inserted pointer, or nullptr should the key already be in use.
|
||||||
*/
|
*/
|
||||||
template <typename ValueType>
|
template <typename T>
|
||||||
[[maybe_unused]] inline AMFValue<ValueType>* Push(const ValueType value) {
|
[[maybe_unused]] inline auto Push(const T value) -> decltype(AMFValue(value))* {
|
||||||
return Insert(m_Dense.size(), value).first;
|
return Insert(m_Dense.size(), value).first;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,4 +350,4 @@ private:
|
|||||||
AMFDense m_Dense;
|
AMFDense m_Dense;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif //!__AMF3__H__
|
#endif //!AMF3_H
|
||||||
|
|||||||
@@ -10,40 +10,54 @@ void RakNet::BitStream::Write<AMFBaseValue&>(AMFBaseValue& value) {
|
|||||||
this->Write(type);
|
this->Write(type);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case eAmf::Integer: {
|
case eAmf::Integer: {
|
||||||
this->Write<AMFIntValue&>(*static_cast<AMFIntValue*>(&value));
|
this->Write<AMFIntValue&>(static_cast<AMFIntValue&>(value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eAmf::Double: {
|
case eAmf::Double: {
|
||||||
this->Write<AMFDoubleValue&>(*static_cast<AMFDoubleValue*>(&value));
|
this->Write<AMFDoubleValue&>(static_cast<AMFDoubleValue&>(value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eAmf::String: {
|
case eAmf::String: {
|
||||||
this->Write<AMFStringValue&>(*static_cast<AMFStringValue*>(&value));
|
this->Write<AMFStringValue&>(static_cast<AMFStringValue&>(value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case eAmf::Array: {
|
case eAmf::Array: {
|
||||||
this->Write<AMFArrayValue&>(*static_cast<AMFArrayValue*>(&value));
|
this->Write<AMFArrayValue&>(static_cast<AMFArrayValue&>(value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
LOG("Encountered unwritable AMFType %i!", type);
|
LOG("Encountered unwritable AMFType %i!", type);
|
||||||
|
[[fallthrough]];
|
||||||
}
|
}
|
||||||
case eAmf::Undefined:
|
case eAmf::Undefined:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::Null:
|
case eAmf::Null:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::False:
|
case eAmf::False:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::True:
|
case eAmf::True:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::Date:
|
case eAmf::Date:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::Object:
|
case eAmf::Object:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::XML:
|
case eAmf::XML:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::XMLDoc:
|
case eAmf::XMLDoc:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::ByteArray:
|
case eAmf::ByteArray:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::VectorInt:
|
case eAmf::VectorInt:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::VectorUInt:
|
case eAmf::VectorUInt:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::VectorDouble:
|
case eAmf::VectorDouble:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::VectorObject:
|
case eAmf::VectorObject:
|
||||||
|
[[fallthrough]];
|
||||||
case eAmf::Dictionary:
|
case eAmf::Dictionary:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -145,8 +159,7 @@ void RakNet::BitStream::Write<AMFIntValue&>(AMFIntValue& value) {
|
|||||||
// Writes an AMFDoubleValue to BitStream
|
// Writes an AMFDoubleValue to BitStream
|
||||||
template<>
|
template<>
|
||||||
void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value) {
|
void RakNet::BitStream::Write<AMFDoubleValue&>(AMFDoubleValue& value) {
|
||||||
double d = value.GetValue();
|
WriteAMFU64(*this, std::bit_cast<uint64_t>(value.GetValue()));
|
||||||
WriteAMFU64(*this, *reinterpret_cast<uint64_t*>(&d));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Writes an AMFStringValue to BitStream
|
// Writes an AMFStringValue to BitStream
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ void WriteSd0Magic(char* input, uint32_t chunkSize) {
|
|||||||
input[2] = '0';
|
input[2] = '0';
|
||||||
input[3] = 0x01;
|
input[3] = 0x01;
|
||||||
input[4] = 0xFF;
|
input[4] = 0xFF;
|
||||||
*reinterpret_cast<uint32_t*>(input + 5) = chunkSize; // Write the integer to the character array
|
std::memcpy(&input[5], &chunkSize, sizeof(uint32_t)); // Write the integer to the character array
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckSd0Magic(std::istream& streamToCheck) {
|
bool CheckSd0Magic(std::istream& streamToCheck) {
|
||||||
|
|||||||
@@ -53,9 +53,9 @@ bool static _IsSuffixChar(const uint8_t c) {
|
|||||||
bool GeneralUtils::details::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
bool GeneralUtils::details::_NextUTF8Char(std::string_view& slice, uint32_t& out) {
|
||||||
const size_t rem = slice.length();
|
const size_t rem = slice.length();
|
||||||
if (slice.empty()) return false;
|
if (slice.empty()) return false;
|
||||||
const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&slice.front());
|
const char* const bytes = slice.data();
|
||||||
if (rem > 0) {
|
if (rem > 0) {
|
||||||
const uint8_t first = bytes[0];
|
const uint8_t first = static_cast<uint8_t>(bytes[0]);
|
||||||
if (first < 0x80) { // 1 byte character
|
if (first < 0x80) { // 1 byte character
|
||||||
out = static_cast<uint32_t>(first & 0x7F);
|
out = static_cast<uint32_t>(first & 0x7F);
|
||||||
slice.remove_prefix(1);
|
slice.remove_prefix(1);
|
||||||
@@ -64,7 +64,7 @@ bool GeneralUtils::details::_NextUTF8Char(std::string_view& slice, uint32_t& out
|
|||||||
// middle byte, not valid at start, fall through
|
// middle byte, not valid at start, fall through
|
||||||
} else if (first < 0xE0) { // two byte character
|
} else if (first < 0xE0) { // two byte character
|
||||||
if (rem > 1) {
|
if (rem > 1) {
|
||||||
const uint8_t second = bytes[1];
|
const uint8_t second = static_cast<uint8_t>(bytes[1]);
|
||||||
if (_IsSuffixChar(second)) {
|
if (_IsSuffixChar(second)) {
|
||||||
out = (static_cast<uint32_t>(first & 0x1F) << 6)
|
out = (static_cast<uint32_t>(first & 0x1F) << 6)
|
||||||
+ static_cast<uint32_t>(second & 0x3F);
|
+ static_cast<uint32_t>(second & 0x3F);
|
||||||
@@ -74,8 +74,8 @@ bool GeneralUtils::details::_NextUTF8Char(std::string_view& slice, uint32_t& out
|
|||||||
}
|
}
|
||||||
} else if (first < 0xF0) { // three byte character
|
} else if (first < 0xF0) { // three byte character
|
||||||
if (rem > 2) {
|
if (rem > 2) {
|
||||||
const uint8_t second = bytes[1];
|
const uint8_t second = static_cast<uint8_t>(bytes[1]);
|
||||||
const uint8_t third = bytes[2];
|
const uint8_t third = static_cast<uint8_t>(bytes[2]);
|
||||||
if (_IsSuffixChar(second) && _IsSuffixChar(third)) {
|
if (_IsSuffixChar(second) && _IsSuffixChar(third)) {
|
||||||
out = (static_cast<uint32_t>(first & 0x0F) << 12)
|
out = (static_cast<uint32_t>(first & 0x0F) << 12)
|
||||||
+ (static_cast<uint32_t>(second & 0x3F) << 6)
|
+ (static_cast<uint32_t>(second & 0x3F) << 6)
|
||||||
@@ -86,9 +86,9 @@ bool GeneralUtils::details::_NextUTF8Char(std::string_view& slice, uint32_t& out
|
|||||||
}
|
}
|
||||||
} else if (first < 0xF8) { // four byte character
|
} else if (first < 0xF8) { // four byte character
|
||||||
if (rem > 3) {
|
if (rem > 3) {
|
||||||
const uint8_t second = bytes[1];
|
const uint8_t second = static_cast<uint8_t>(bytes[1]);
|
||||||
const uint8_t third = bytes[2];
|
const uint8_t third = static_cast<uint8_t>(bytes[2]);
|
||||||
const uint8_t fourth = bytes[3];
|
const uint8_t fourth = static_cast<uint8_t>(bytes[3]);
|
||||||
if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) {
|
if (_IsSuffixChar(second) && _IsSuffixChar(third) && _IsSuffixChar(fourth)) {
|
||||||
out = (static_cast<uint32_t>(first & 0x07) << 18)
|
out = (static_cast<uint32_t>(first & 0x07) << 18)
|
||||||
+ (static_cast<uint32_t>(second & 0x3F) << 12)
|
+ (static_cast<uint32_t>(second & 0x3F) << 12)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
// C++
|
// C++
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@@ -145,7 +146,7 @@ namespace GeneralUtils {
|
|||||||
template <typename... Bases>
|
template <typename... Bases>
|
||||||
struct overload : Bases... {
|
struct overload : Bases... {
|
||||||
using is_transparent = void;
|
using is_transparent = void;
|
||||||
using Bases::operator() ... ;
|
using Bases::operator()...;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct char_pointer_hash {
|
struct char_pointer_hash {
|
||||||
@@ -160,6 +161,26 @@ namespace GeneralUtils {
|
|||||||
char_pointer_hash
|
char_pointer_hash
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A convenience wrapper around std::memcpy that creates a new object
|
||||||
|
* from the value representation of the provided bytes.Use when
|
||||||
|
* std::bit_cast is not applicable.
|
||||||
|
* @warning All restrictions of std::memcpy still apply. Accessing
|
||||||
|
* outside of the source object is undefined behavior.
|
||||||
|
* @param from The source of the value representation
|
||||||
|
* @returns A new object with the given value representation
|
||||||
|
*/
|
||||||
|
template <typename To, typename From>
|
||||||
|
[[nodiscard]]
|
||||||
|
inline To FromBitsUnchecked(const From* from) noexcept
|
||||||
|
requires (std::is_trivially_copyable_v<To>
|
||||||
|
&& std::is_trivially_copyable_v<From>)
|
||||||
|
{
|
||||||
|
To to{};
|
||||||
|
std::memcpy(&to, from, sizeof(To));
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
// Concept constraining to enum types
|
// Concept constraining to enum types
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept Enum = std::is_enum_v<T>;
|
concept Enum = std::is_enum_v<T>;
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ struct AssetStream : std::istream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
operator bool() {
|
operator bool() {
|
||||||
|
// NEED TO FIX THIS
|
||||||
return reinterpret_cast<AssetMemoryBuffer*>(rdbuf())->m_Success;
|
return reinterpret_cast<AssetMemoryBuffer*>(rdbuf())->m_Success;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -957,6 +957,7 @@ namespace MessageType {
|
|||||||
MODIFY_PLAYER_ZONE_STATISTIC = 1046,
|
MODIFY_PLAYER_ZONE_STATISTIC = 1046,
|
||||||
APPLY_EXTERNAL_FORCE = 1049,
|
APPLY_EXTERNAL_FORCE = 1049,
|
||||||
GET_APPLIED_EXTERNAL_FORCE = 1050,
|
GET_APPLIED_EXTERNAL_FORCE = 1050,
|
||||||
|
ACTIVITY_NOTIFY = 1051,
|
||||||
ITEM_EQUIPPED = 1052,
|
ITEM_EQUIPPED = 1052,
|
||||||
ACTIVITY_STATE_CHANGE_REQUEST = 1053,
|
ACTIVITY_STATE_CHANGE_REQUEST = 1053,
|
||||||
OVERRIDE_FRICTION = 1054,
|
OVERRIDE_FRICTION = 1054,
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
|
|
||||||
namespace MessageType {
|
namespace MessageType {
|
||||||
enum class World : uint32_t {
|
enum class World : uint32_t {
|
||||||
VALIDATION = 1, // Session info
|
INVALID = 0,
|
||||||
|
VALIDATION, // Session info
|
||||||
CHARACTER_LIST_REQUEST,
|
CHARACTER_LIST_REQUEST,
|
||||||
CHARACTER_CREATE_REQUEST,
|
CHARACTER_CREATE_REQUEST,
|
||||||
LOGIN_REQUEST, // Character selected
|
LOGIN_REQUEST, // Character selected
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public:
|
|||||||
uint32_t lastPlayedTimestamp{};
|
uint32_t lastPlayedTimestamp{};
|
||||||
float primaryScore{};
|
float primaryScore{};
|
||||||
float secondaryScore{};
|
float secondaryScore{};
|
||||||
uint32_t tertiaryScore{};
|
float tertiaryScore{};
|
||||||
uint32_t numWins{};
|
uint32_t numWins{};
|
||||||
uint32_t numTimesPlayed{};
|
uint32_t numTimesPlayed{};
|
||||||
uint32_t ranking{};
|
uint32_t ranking{};
|
||||||
|
|||||||
@@ -1493,6 +1493,14 @@ void Entity::OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16s
|
|||||||
GetScript()->OnChoiceBoxResponse(this, sender, button, buttonIdentifier, identifier);
|
GetScript()->OnChoiceBoxResponse(this, sender, button, buttonIdentifier, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Entity::OnActivityNotify(GameMessages::ActivityNotify& notify) {
|
||||||
|
GetScript()->OnActivityNotify(this, notify);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Entity::OnShootingGalleryFire(GameMessages::ShootingGalleryFire& fire) {
|
||||||
|
GetScript()->OnShootingGalleryFire(*this, fire);
|
||||||
|
}
|
||||||
|
|
||||||
void Entity::RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled) {
|
void Entity::RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled) {
|
||||||
GetScript()->OnRequestActivityExit(sender, player, canceled);
|
GetScript()->OnRequestActivityExit(sender, player, canceled);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,11 @@
|
|||||||
#include "eKillType.h"
|
#include "eKillType.h"
|
||||||
#include "Observable.h"
|
#include "Observable.h"
|
||||||
|
|
||||||
|
namespace GameMessages {
|
||||||
|
struct ActivityNotify;
|
||||||
|
struct ShootingGalleryFire;
|
||||||
|
};
|
||||||
|
|
||||||
namespace Loot {
|
namespace Loot {
|
||||||
class Info;
|
class Info;
|
||||||
};
|
};
|
||||||
@@ -210,6 +215,8 @@ public:
|
|||||||
void OnZonePropertyModelRemoved(Entity* player);
|
void OnZonePropertyModelRemoved(Entity* player);
|
||||||
void OnZonePropertyModelRemovedWhileEquipped(Entity* player);
|
void OnZonePropertyModelRemovedWhileEquipped(Entity* player);
|
||||||
void OnZonePropertyModelRotated(Entity* player);
|
void OnZonePropertyModelRotated(Entity* player);
|
||||||
|
void OnActivityNotify(GameMessages::ActivityNotify& notify);
|
||||||
|
void OnShootingGalleryFire(GameMessages::ShootingGalleryFire& notify);
|
||||||
|
|
||||||
void OnMessageBoxResponse(Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData);
|
void OnMessageBoxResponse(Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData);
|
||||||
void OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier);
|
void OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16string& buttonIdentifier, const std::u16string& identifier);
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ void QueryToLdf(Leaderboard& leaderboard, const std::vector<ILeaderboard::Entry>
|
|||||||
// Score:1
|
// Score:1
|
||||||
entry.push_back(new LDFData<int32_t>(u"Streak", leaderboardEntry.secondaryScore));
|
entry.push_back(new LDFData<int32_t>(u"Streak", leaderboardEntry.secondaryScore));
|
||||||
// Streak:1
|
// Streak:1
|
||||||
entry.push_back(new LDFData<float>(u"HitPercentage", (leaderboardEntry.tertiaryScore / 100.0f)));
|
entry.push_back(new LDFData<float>(u"HitPercentage", leaderboardEntry.tertiaryScore));
|
||||||
// HitPercentage:3 between 0 and 1
|
// HitPercentage:3 between 0 and 1
|
||||||
break;
|
break;
|
||||||
case Racing:
|
case Racing:
|
||||||
@@ -199,9 +199,9 @@ std::vector<ILeaderboard::Entry> FilterFriends(const std::vector<ILeaderboard::E
|
|||||||
std::vector<ILeaderboard::Entry> friendsLeaderboard;
|
std::vector<ILeaderboard::Entry> friendsLeaderboard;
|
||||||
for (const auto& entry : leaderboard) {
|
for (const auto& entry : leaderboard) {
|
||||||
const auto res = std::ranges::find_if(friendOfPlayer, [&entry, relatedPlayer](const FriendData& data) {
|
const auto res = std::ranges::find_if(friendOfPlayer, [&entry, relatedPlayer](const FriendData& data) {
|
||||||
return entry.charId == data.friendID || entry.charId == relatedPlayer;
|
return entry.charId == data.friendID;
|
||||||
});
|
});
|
||||||
if (res != friendOfPlayer.cend()) {
|
if (res != friendOfPlayer.cend() || entry.charId == relatedPlayer) {
|
||||||
friendsLeaderboard.push_back(entry);
|
friendsLeaderboard.push_back(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,9 +69,10 @@ InventoryComponent::InventoryComponent(Entity* parent) : Component(parent) {
|
|||||||
auto slot = 0u;
|
auto slot = 0u;
|
||||||
|
|
||||||
for (const auto& item : items) {
|
for (const auto& item : items) {
|
||||||
if (!item.equip || !Inventory::IsValidItem(item.itemid)) {
|
if (!Inventory::IsValidItem(item.itemid)) continue;
|
||||||
continue;
|
AddItem(item.itemid, item.count);
|
||||||
}
|
|
||||||
|
if (!item.equip) continue;
|
||||||
|
|
||||||
const LWOOBJID id = ObjectIDManager::GenerateObjectID();
|
const LWOOBJID id = ObjectIDManager::GenerateObjectID();
|
||||||
|
|
||||||
|
|||||||
@@ -265,6 +265,7 @@ void MovementAIComponent::PullToPoint(const NiPoint3& point) {
|
|||||||
|
|
||||||
void MovementAIComponent::SetPath(std::vector<PathWaypoint> path) {
|
void MovementAIComponent::SetPath(std::vector<PathWaypoint> path) {
|
||||||
if (path.empty()) return;
|
if (path.empty()) return;
|
||||||
|
while (!m_CurrentPath.empty()) m_CurrentPath.pop();
|
||||||
std::for_each(path.rbegin(), path.rend() - 1, [this](const PathWaypoint& point) {
|
std::for_each(path.rbegin(), path.rend() - 1, [this](const PathWaypoint& point) {
|
||||||
this->m_CurrentPath.push(point);
|
this->m_CurrentPath.push(point);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) {
|
|||||||
|
|
||||||
GameMessages::SendRegisterPetDBID(m_Tamer, petSubKey, tamer->GetSystemAddress());
|
GameMessages::SendRegisterPetDBID(m_Tamer, petSubKey, tamer->GetSystemAddress());
|
||||||
|
|
||||||
inventoryComponent->AddItem(m_Parent->GetLOT(), 1, eLootSourceType::ACTIVITY, eInventoryType::MODELS, {}, LWOOBJID_EMPTY, true, false, petSubKey);
|
inventoryComponent->AddItem(m_Parent->GetLOT(), 1, eLootSourceType::INVENTORY, eInventoryType::MODELS, {}, LWOOBJID_EMPTY, true, false, petSubKey);
|
||||||
auto* item = inventoryComponent->FindItemBySubKey(petSubKey, MODELS);
|
auto* item = inventoryComponent->FindItemBySubKey(petSubKey, MODELS);
|
||||||
|
|
||||||
if (item == nullptr) {
|
if (item == nullptr) {
|
||||||
|
|||||||
@@ -123,6 +123,11 @@ void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::B
|
|||||||
behavior->Handle(sync_entry.context, bitStream, branch);
|
behavior->Handle(sync_entry.context, bitStream, branch);
|
||||||
|
|
||||||
this->m_managedProjectiles.erase(this->m_managedProjectiles.begin() + index);
|
this->m_managedProjectiles.erase(this->m_managedProjectiles.begin() + index);
|
||||||
|
|
||||||
|
GameMessages::ActivityNotify notify;
|
||||||
|
notify.notification.push_back( std::make_unique<LDFData<int32_t>>(u"shot_done", sync_entry.skillId));
|
||||||
|
|
||||||
|
m_Parent->OnActivityNotify(notify);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, const LOT lot) {
|
void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, BehaviorContext* context, const BehaviorBranchContext& branch, const LOT lot) {
|
||||||
@@ -132,6 +137,7 @@ void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, Behav
|
|||||||
entry.branchContext = branch;
|
entry.branchContext = branch;
|
||||||
entry.lot = lot;
|
entry.lot = lot;
|
||||||
entry.id = projectileId;
|
entry.id = projectileId;
|
||||||
|
entry.skillId = context->skillID;
|
||||||
|
|
||||||
this->m_managedProjectiles.push_back(entry);
|
this->m_managedProjectiles.push_back(entry);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ struct ProjectileSyncEntry {
|
|||||||
|
|
||||||
BehaviorBranchContext branchContext{ 0, 0 };
|
BehaviorBranchContext branchContext{ 0, 0 };
|
||||||
|
|
||||||
|
int32_t skillId{ 0 };
|
||||||
|
|
||||||
explicit ProjectileSyncEntry();
|
explicit ProjectileSyncEntry();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -703,6 +703,12 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
|
|||||||
case MessageType::Game::UPDATE_INVENTORY_GROUP_CONTENTS:
|
case MessageType::Game::UPDATE_INVENTORY_GROUP_CONTENTS:
|
||||||
GameMessages::HandleUpdateInventoryGroupContents(inStream, entity, sysAddr);
|
GameMessages::HandleUpdateInventoryGroupContents(inStream, entity, sysAddr);
|
||||||
break;
|
break;
|
||||||
|
case MessageType::Game::SHOOTING_GALLERY_FIRE: {
|
||||||
|
GameMessages::ShootingGalleryFire fire{};
|
||||||
|
fire.Deserialize(inStream);
|
||||||
|
fire.Handle(*entity, sysAddr);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data());
|
LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data());
|
||||||
|
|||||||
@@ -6395,4 +6395,35 @@ namespace GameMessages {
|
|||||||
bitStream.Write(targetPosition.y);
|
bitStream.Write(targetPosition.y);
|
||||||
bitStream.Write(targetPosition.z);
|
bitStream.Write(targetPosition.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetModelToBuild::Serialize(RakNet::BitStream& bitStream) const {
|
||||||
|
bitStream.Write(modelLot != -1);
|
||||||
|
if (modelLot != -1) bitStream.Write(modelLot);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpawnModelBricks::Serialize(RakNet::BitStream& bitStream) const {
|
||||||
|
bitStream.Write(amount != 0.0f);
|
||||||
|
if (amount != 0.0f) bitStream.Write(amount);
|
||||||
|
bitStream.Write(position != NiPoint3Constant::ZERO);
|
||||||
|
if (position != NiPoint3Constant::ZERO) {
|
||||||
|
bitStream.Write(position.x);
|
||||||
|
bitStream.Write(position.y);
|
||||||
|
bitStream.Write(position.z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ShootingGalleryFire::Deserialize(RakNet::BitStream& bitStream) {
|
||||||
|
if (!bitStream.Read(target.x)) return false;
|
||||||
|
if (!bitStream.Read(target.y)) return false;
|
||||||
|
if (!bitStream.Read(target.z)) return false;
|
||||||
|
if (!bitStream.Read(rotation.w)) return false;
|
||||||
|
if (!bitStream.Read(rotation.x)) return false;
|
||||||
|
if (!bitStream.Read(rotation.y)) return false;
|
||||||
|
if (!bitStream.Read(rotation.z)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShootingGalleryFire::Handle(Entity& entity, const SystemAddress& sysAddr) {
|
||||||
|
entity.OnShootingGalleryFire(*this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ namespace GameMessages {
|
|||||||
virtual ~GameMsg() = default;
|
virtual ~GameMsg() = default;
|
||||||
void Send(const SystemAddress& sysAddr) const;
|
void Send(const SystemAddress& sysAddr) const;
|
||||||
virtual void Serialize(RakNet::BitStream& bitStream) const {}
|
virtual void Serialize(RakNet::BitStream& bitStream) const {}
|
||||||
|
virtual bool Deserialize(RakNet::BitStream& bitStream) { return true; }
|
||||||
|
virtual void Handle(Entity& entity, const SystemAddress& sysAddr) {};
|
||||||
MessageType::Game msgId;
|
MessageType::Game msgId;
|
||||||
LWOOBJID target{ LWOOBJID_EMPTY };
|
LWOOBJID target{ LWOOBJID_EMPTY };
|
||||||
};
|
};
|
||||||
@@ -727,6 +729,35 @@ namespace GameMessages {
|
|||||||
ConfigureRacingControl() : GameMsg(MessageType::Game::CONFIGURE_RACING_CONTROL) {}
|
ConfigureRacingControl() : GameMsg(MessageType::Game::CONFIGURE_RACING_CONTROL) {}
|
||||||
std::vector<std::unique_ptr<LDFBaseData>> racingSettings{};
|
std::vector<std::unique_ptr<LDFBaseData>> racingSettings{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct SetModelToBuild : public GameMsg {
|
||||||
|
SetModelToBuild() : GameMsg(MessageType::Game::SET_MODEL_TO_BUILD) {}
|
||||||
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
||||||
|
LOT modelLot{ -1 };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SpawnModelBricks : public GameMsg {
|
||||||
|
SpawnModelBricks() : GameMsg(MessageType::Game::SPAWN_MODEL_BRICKS) {}
|
||||||
|
void Serialize(RakNet::BitStream& bitStream) const override;
|
||||||
|
|
||||||
|
float amount{ 0.0f };
|
||||||
|
NiPoint3 position{ NiPoint3Constant::ZERO };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ActivityNotify : public GameMsg {
|
||||||
|
ActivityNotify() : GameMsg(MessageType::Game::ACTIVITY_NOTIFY) {}
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<LDFBaseData>> notification{};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ShootingGalleryFire : public GameMsg {
|
||||||
|
ShootingGalleryFire() : GameMsg(MessageType::Game::SHOOTING_GALLERY_FIRE) {}
|
||||||
|
bool Deserialize(RakNet::BitStream& bitStream) override;
|
||||||
|
void Handle(Entity& entity, const SystemAddress& sysAddr) override;
|
||||||
|
|
||||||
|
NiPoint3 target{};
|
||||||
|
NiQuaternion rotation{};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // GAMEMESSAGES_H
|
#endif // GAMEMESSAGES_H
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ void NpcAgCourseStarter::OnFireEventServerSide(Entity* self, Entity* sender, std
|
|||||||
LWOOBJID_EMPTY, "", senderSysAddr);
|
LWOOBJID_EMPTY, "", senderSysAddr);
|
||||||
scriptedActivityComponent->RemoveActivityPlayerData(senderId);
|
scriptedActivityComponent->RemoveActivityPlayerData(senderId);
|
||||||
} else if (args == "course_finish") {
|
} else if (args == "course_finish") {
|
||||||
|
|
||||||
const auto raceEndTime = Game::server->GetUptime();
|
const auto raceEndTime = Game::server->GetUptime();
|
||||||
const auto fRaceEndTime = std::chrono::duration<float, std::ratio<1>>(raceEndTime).count();
|
const auto fRaceEndTime = std::chrono::duration<float, std::ratio<1>>(raceEndTime).count();
|
||||||
const auto raceTimeElapsed = fRaceEndTime - data->values[1];
|
const auto raceTimeElapsed = fRaceEndTime - data->values[1];
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ void VeBricksampleServer::OnUse(Entity* self, Entity* user) {
|
|||||||
auto* inventoryComponent = user->GetComponent<InventoryComponent>();
|
auto* inventoryComponent = user->GetComponent<InventoryComponent>();
|
||||||
|
|
||||||
if (loot && inventoryComponent != nullptr && inventoryComponent->GetLotCount(loot) == 0) {
|
if (loot && inventoryComponent != nullptr && inventoryComponent->GetLotCount(loot) == 0) {
|
||||||
inventoryComponent->AddItem(loot, 1, eLootSourceType::ACTIVITY);
|
inventoryComponent->AddItem(loot, 1, eLootSourceType::NONE);
|
||||||
|
|
||||||
for (auto* brickEntity : Game::entityManager->GetEntitiesInGroup("Bricks")) {
|
for (auto* brickEntity : Game::entityManager->GetEntitiesInGroup("Bricks")) {
|
||||||
GameMessages::SendNotifyClientObject(brickEntity->GetObjectID(), u"Pickedup");
|
GameMessages::SendNotifyClientObject(brickEntity->GetObjectID(), u"Pickedup");
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ void VeMissionConsole::OnUse(Entity* self, Entity* user) {
|
|||||||
|
|
||||||
auto* inventoryComponent = user->GetComponent<InventoryComponent>();
|
auto* inventoryComponent = user->GetComponent<InventoryComponent>();
|
||||||
if (inventoryComponent != nullptr) {
|
if (inventoryComponent != nullptr) {
|
||||||
inventoryComponent->AddItem(12547, 1, eLootSourceType::ACTIVITY); // Add the panel required for pickup
|
inventoryComponent->AddItem(12547, 1, eLootSourceType::NONE); // Add the panel required for pickup
|
||||||
}
|
}
|
||||||
|
|
||||||
// The flag to set is 101<number>
|
// The flag to set is 101<number>
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ int32_t ActivityManager::GetGameID(Entity* self) const {
|
|||||||
|
|
||||||
float_t ActivityManager::ActivityTimerGetRemainingTime(Entity* self, const std::string& timerName) const {
|
float_t ActivityManager::ActivityTimerGetRemainingTime(Entity* self, const std::string& timerName) const {
|
||||||
auto* timer = GetTimer(timerName);
|
auto* timer = GetTimer(timerName);
|
||||||
return timer != nullptr ? std::min(timer->stopTime - timer->runTime, 0.0f) : 0.0f;
|
return timer != nullptr ? std::max(timer->stopTime - timer->runTime, 0.0f) : 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ActivityManager::ActivityTimerReset(Entity* self, const std::string& timerName) {
|
void ActivityManager::ActivityTimerReset(Entity* self, const std::string& timerName) {
|
||||||
|
|||||||
@@ -357,6 +357,22 @@ namespace CppScripts {
|
|||||||
virtual void OnRequestActivityExit(Entity* sender, LWOOBJID player, bool canceled) {};
|
virtual void OnRequestActivityExit(Entity* sender, LWOOBJID player, bool canceled) {};
|
||||||
|
|
||||||
virtual void OnZoneLoadedInfo(Entity* self, const GameMessages::ZoneLoadedInfo& info) {};
|
virtual void OnZoneLoadedInfo(Entity* self, const GameMessages::ZoneLoadedInfo& info) {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles notifying when activity data is done
|
||||||
|
*
|
||||||
|
* @param self
|
||||||
|
* @param notify The parameters of the notification
|
||||||
|
*/
|
||||||
|
virtual void OnActivityNotify(Entity* self, GameMessages::ActivityNotify& notify) {};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief handles shooting gallery fire
|
||||||
|
*
|
||||||
|
* @param self
|
||||||
|
* @param fire The firing data
|
||||||
|
*/
|
||||||
|
virtual void OnShootingGalleryFire(Entity& self, GameMessages::ShootingGalleryFire& fire) {};
|
||||||
};
|
};
|
||||||
|
|
||||||
Script* const GetScript(Entity* parent, const std::string& scriptName);
|
Script* const GetScript(Entity* parent, const std::string& scriptName);
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
#include "eReplicaComponentType.h"
|
#include "eReplicaComponentType.h"
|
||||||
#include "RenderComponent.h"
|
#include "RenderComponent.h"
|
||||||
#include "eGameActivity.h"
|
#include "eGameActivity.h"
|
||||||
|
#include "Item.h"
|
||||||
|
#include <ranges>
|
||||||
|
|
||||||
void SGCannon::OnStartup(Entity* self) {
|
void SGCannon::OnStartup(Entity* self) {
|
||||||
LOG("OnStartup");
|
LOG("OnStartup");
|
||||||
@@ -81,10 +83,6 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int
|
|||||||
auto* player = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable));
|
auto* player = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable));
|
||||||
if (player != nullptr) {
|
if (player != nullptr) {
|
||||||
LOG("Player is ready");
|
LOG("Player is ready");
|
||||||
/*GameMessages::SendSetStunned(player->GetObjectID(), eStateChangeType::PUSH, player->GetSystemAddress(), LWOOBJID_EMPTY,
|
|
||||||
true, true, true, true, true, true, true);*/
|
|
||||||
|
|
||||||
LOG("Sending ActivityEnter");
|
|
||||||
|
|
||||||
GameMessages::SendActivityEnter(self->GetObjectID(), player->GetSystemAddress());
|
GameMessages::SendActivityEnter(self->GetObjectID(), player->GetSystemAddress());
|
||||||
|
|
||||||
@@ -103,7 +101,6 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int
|
|||||||
auto* characterComponent = player->GetComponent<CharacterComponent>();
|
auto* characterComponent = player->GetComponent<CharacterComponent>();
|
||||||
|
|
||||||
if (characterComponent != nullptr) {
|
if (characterComponent != nullptr) {
|
||||||
characterComponent->SetIsRacing(true);
|
|
||||||
characterComponent->SetCurrentActivity(eGameActivity::SHOOTING_GALLERY);
|
characterComponent->SetCurrentActivity(eGameActivity::SHOOTING_GALLERY);
|
||||||
auto possessor = player->GetComponent<PossessorComponent>();
|
auto possessor = player->GetComponent<PossessorComponent>();
|
||||||
if (possessor) {
|
if (possessor) {
|
||||||
@@ -114,20 +111,12 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int
|
|||||||
Game::entityManager->SerializeEntity(player);
|
Game::entityManager->SerializeEntity(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
self->SetNetworkVar<bool>(HideScoreBoardVariable, true);
|
self->AddCallbackTimer(1.0f, [self, this]() {
|
||||||
self->SetNetworkVar<bool>(ReSetSuperChargeVariable, true);
|
self->SetNetworkVar<bool>(HideScoreBoardVariable, true);
|
||||||
self->SetNetworkVar<bool>(ShowLoadingUI, true);
|
self->SetNetworkVar<bool>(ReSetSuperChargeVariable, true);
|
||||||
|
self->SetNetworkVar<bool>(ShowLoadingUI, true);
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
|
||||||
GameMessages::SendTeleport(
|
|
||||||
player->GetObjectID(),
|
|
||||||
{-292.6415710449219, 230.20237731933594, -3.9090466499328613},
|
|
||||||
{0.7067984342575073, -6.527870573336259e-05, 0.707414984703064, 0.00021762956748716533},
|
|
||||||
player->GetSystemAddress(), true
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
|
|
||||||
//GameMessages::SendRequestActivityEnter(self->GetObjectID(), player->GetSystemAddress(), false, player->GetObjectID());
|
|
||||||
} else {
|
} else {
|
||||||
LOG("Player not found");
|
LOG("Player not found");
|
||||||
}
|
}
|
||||||
@@ -245,14 +234,6 @@ void SGCannon::GameOverTimerFunc(Entity* self) {
|
|||||||
|
|
||||||
GameMessages::SendActivityPause(self->GetObjectID(), true, player->GetSystemAddress());
|
GameMessages::SendActivityPause(self->GetObjectID(), true, player->GetSystemAddress());
|
||||||
|
|
||||||
/*const auto leftoverCannonballs = Game::entityManager->GetEntitiesInGroup("cannonball");
|
|
||||||
if (leftoverCannonballs.empty()) {
|
|
||||||
RecordPlayerScore(self);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
ActivityTimerStart(self, EndGameBufferTimer, 1, leftoverCannonballs.size());
|
|
||||||
}*/
|
|
||||||
|
|
||||||
ActivityTimerStart(self, EndGameBufferTimer, 1, 1);
|
ActivityTimerStart(self, EndGameBufferTimer, 1, 1);
|
||||||
|
|
||||||
TimerToggle(self);
|
TimerToggle(self);
|
||||||
@@ -261,60 +242,51 @@ void SGCannon::GameOverTimerFunc(Entity* self) {
|
|||||||
|
|
||||||
void SGCannon::DoSpawnTimerFunc(Entity* self, const std::string& name) {
|
void SGCannon::DoSpawnTimerFunc(Entity* self, const std::string& name) {
|
||||||
if (self->GetVar<bool>(GameStartedVariable)) {
|
if (self->GetVar<bool>(GameStartedVariable)) {
|
||||||
LOG_DEBUG("time name %s %s", name.c_str(), name.substr(7).c_str());
|
|
||||||
const auto spawnNumber = static_cast<uint32_t>(std::stoi(name.substr(7)));
|
const auto spawnNumber = static_cast<uint32_t>(std::stoi(name.substr(7)));
|
||||||
const auto& activeSpawns = self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable);
|
const auto& activeSpawns = self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable);
|
||||||
LOG_DEBUG("size %i, %i", activeSpawns.size(), spawnNumber);
|
|
||||||
if (activeSpawns.size() <= spawnNumber) {
|
if (activeSpawns.size() <= spawnNumber) {
|
||||||
LOG_DEBUG("Trying to spawn %i when spawns size is only %i", spawnNumber, activeSpawns.size());
|
LOG_DEBUG("Trying to spawn %i when spawns size is only %i", spawnNumber, activeSpawns.size());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto& toSpawn = activeSpawns.at(spawnNumber);
|
const auto& toSpawn = activeSpawns.at(spawnNumber);
|
||||||
LOG_DEBUG("toSpawn %i", toSpawn.spawnPaths.size());
|
const auto pathIndex = GeneralUtils::GenerateRandomNumber<size_t>(0, toSpawn.spawnPaths.size() - 1);
|
||||||
const auto pathIndex = GeneralUtils::GenerateRandomNumber<float_t>(0, toSpawn.spawnPaths.size() - 1);
|
|
||||||
LOG_DEBUG("index %f", pathIndex);
|
|
||||||
LOG_DEBUG("%s", toSpawn.spawnPaths.at(pathIndex).c_str());
|
|
||||||
const auto* path = Game::zoneManager->GetZone()->GetPath(toSpawn.spawnPaths.at(pathIndex));
|
const auto* path = Game::zoneManager->GetZone()->GetPath(toSpawn.spawnPaths.at(pathIndex));
|
||||||
if (!path) {
|
if (!path || path->pathWaypoints.empty()) {
|
||||||
LOG_DEBUG("Path %s at index %i is null", toSpawn.spawnPaths.at(pathIndex).c_str(), pathIndex);
|
LOG_DEBUG("Path %s at index %i or has 0 waypoints", toSpawn.spawnPaths.at(pathIndex).c_str(), pathIndex);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DEBUG("%s", path->pathName.c_str());
|
|
||||||
|
|
||||||
auto info = EntityInfo{};
|
auto info = EntityInfo{};
|
||||||
info.lot = toSpawn.lot;
|
info.lot = toSpawn.lot;
|
||||||
info.spawnerID = self->GetObjectID();
|
info.spawnerID = self->GetObjectID();
|
||||||
info.pos = path->pathWaypoints.at(0).position;
|
info.pos = path->pathWaypoints[0].position;
|
||||||
|
|
||||||
info.settings = {
|
info.settings = {
|
||||||
new LDFData<SGEnemy>(u"SpawnData", toSpawn),
|
new LDFData<SGEnemy>(u"SpawnData", toSpawn),
|
||||||
new LDFData<std::string>(u"custom_script_server", "scripts/ai/ACT/SG_TARGET.lua"),
|
new LDFData<std::string>(u"custom_script_server", "scripts/ai/ACT/SG_TARGET.lua"), // this script is never loaded
|
||||||
new LDFData<std::string>(u"custom_script_client", "scripts/client/ai/SG_TARGET_CLIENT.lua"),
|
new LDFData<std::string>(u"custom_script_client", "scripts/client/ai/SG_TARGET_CLIENT.lua"),
|
||||||
new LDFData<std::string>(u"attached_path", path->pathName),
|
new LDFData<std::string>(u"attached_path", path->pathName),
|
||||||
new LDFData<uint32_t>(u"attached_path_start", 0),
|
new LDFData<uint32_t>(u"attached_path_start", 0),
|
||||||
new LDFData<std::u16string>(u"groupID", u"SGEnemy")
|
new LDFData<std::u16string>(u"groupID", u"SGEnemy"),
|
||||||
|
new LDFData<uint32_t>(u"wave", self->GetVar<uint32_t>(ThisWaveVariable)),
|
||||||
};
|
};
|
||||||
|
|
||||||
LOG_DEBUG("Spawning enemy %i on path %s", toSpawn.lot, path->pathName.c_str());
|
|
||||||
|
|
||||||
auto* enemy = Game::entityManager->CreateEntity(info, nullptr, self);
|
auto* enemy = Game::entityManager->CreateEntity(info, nullptr, self);
|
||||||
Game::entityManager->ConstructEntity(enemy);
|
|
||||||
|
|
||||||
auto* movementAI = enemy->AddComponent<MovementAIComponent>(MovementAIInfo{});
|
auto* movementAI = enemy->AddComponent<MovementAIComponent>(MovementAIInfo{});
|
||||||
|
auto* simplePhysicsComponent = enemy->GetComponent<SimplePhysicsComponent>();
|
||||||
|
if (simplePhysicsComponent) {
|
||||||
|
simplePhysicsComponent->SetPhysicsMotionState(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
Game::entityManager->ConstructEntity(enemy);
|
||||||
|
|
||||||
movementAI->SetMaxSpeed(toSpawn.initialSpeed);
|
movementAI->SetMaxSpeed(toSpawn.initialSpeed);
|
||||||
movementAI->SetCurrentSpeed(toSpawn.initialSpeed);
|
movementAI->SetCurrentSpeed(toSpawn.initialSpeed);
|
||||||
movementAI->SetHaltDistance(0.0f);
|
movementAI->SetHaltDistance(0.0f);
|
||||||
|
|
||||||
std::vector<PathWaypoint> pathWaypoints = path->pathWaypoints;
|
movementAI->SetPath(path->pathWaypoints);
|
||||||
|
|
||||||
if (GeneralUtils::GenerateRandomNumber<float_t>(0, 1) < 0.5f) {
|
|
||||||
std::reverse(pathWaypoints.begin(), pathWaypoints.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
movementAI->SetPath(pathWaypoints);
|
|
||||||
|
|
||||||
enemy->AddDieCallback([this, self, enemy, name]() {
|
enemy->AddDieCallback([this, self, enemy, name]() {
|
||||||
RegisterHit(self, enemy, name);
|
RegisterHit(self, enemy, name);
|
||||||
@@ -362,7 +334,10 @@ void SGCannon::StartGame(Entity* self) {
|
|||||||
|
|
||||||
auto rewardObjects = Game::entityManager->GetEntitiesInGroup(constants.rewardModelGroup);
|
auto rewardObjects = Game::entityManager->GetEntitiesInGroup(constants.rewardModelGroup);
|
||||||
for (auto* reward : rewardObjects) {
|
for (auto* reward : rewardObjects) {
|
||||||
reward->OnFireEventServerSide(self, ModelToBuildEvent);
|
GameMessages::SetModelToBuild modelToBuild{};
|
||||||
|
modelToBuild.modelLot = LOT_NULL;
|
||||||
|
modelToBuild.target = reward->GetObjectID();
|
||||||
|
modelToBuild.Send(UNASSIGNED_SYSTEM_ADDRESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* player = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable));
|
auto* player = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable));
|
||||||
@@ -400,6 +375,10 @@ void SGCannon::DoGameStartup(Entity* self) {
|
|||||||
constants.firstWaveStartTime);
|
constants.firstWaveStartTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SGCannon::OnShootingGalleryFire(Entity& self, GameMessages::ShootingGalleryFire& fire) {
|
||||||
|
self.SetVar<uint32_t>(ShotsFiredVariable, self.GetVar<uint32_t>(ShotsFiredVariable) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
void SGCannon::SpawnNewModel(Entity* self) {
|
void SGCannon::SpawnNewModel(Entity* self) {
|
||||||
|
|
||||||
// Add a new reward to the existing rewards
|
// Add a new reward to the existing rewards
|
||||||
@@ -407,6 +386,7 @@ void SGCannon::SpawnNewModel(Entity* self) {
|
|||||||
if (currentReward != -1) {
|
if (currentReward != -1) {
|
||||||
auto rewards = self->GetVar<std::vector<LOT>>(RewardsVariable);
|
auto rewards = self->GetVar<std::vector<LOT>>(RewardsVariable);
|
||||||
rewards.push_back(currentReward);
|
rewards.push_back(currentReward);
|
||||||
|
self->SetVar<std::vector<LOT>>(RewardsVariable, rewards);
|
||||||
self->SetNetworkVar<int32_t>(RewardAddedVariable, currentReward);
|
self->SetNetworkVar<int32_t>(RewardAddedVariable, currentReward);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,9 +418,13 @@ void SGCannon::SpawnNewModel(Entity* self) {
|
|||||||
std::unordered_map<LOT, int32_t> toDrop = {};
|
std::unordered_map<LOT, int32_t> toDrop = {};
|
||||||
toDrop = Loot::RollLootMatrix(player, lootMatrix);
|
toDrop = Loot::RollLootMatrix(player, lootMatrix);
|
||||||
|
|
||||||
for (auto drop : toDrop) {
|
for (const auto [lot, count] : toDrop) {
|
||||||
rewardModel->OnFireEventServerSide(self, ModelToBuildEvent, drop.first);
|
GameMessages::SetModelToBuild modelToBuild{};
|
||||||
self->SetVar<LOT>(CurrentRewardVariable, drop.first);
|
modelToBuild.modelLot = lot;
|
||||||
|
modelToBuild.target = rewardModel->GetObjectID();
|
||||||
|
modelToBuild.Send(player->GetSystemAddress());
|
||||||
|
|
||||||
|
self->SetVar<LOT>(CurrentRewardVariable, lot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -514,11 +498,11 @@ void SGCannon::RecordPlayerScore(Entity* self) {
|
|||||||
const auto currentWave = self->GetVar<uint32_t>(ThisWaveVariable);
|
const auto currentWave = self->GetVar<uint32_t>(ThisWaveVariable);
|
||||||
|
|
||||||
if (currentWave > 0) {
|
if (currentWave > 0) {
|
||||||
auto totalWaveScore = 0;
|
auto totalWaveScore = totalScore;
|
||||||
auto playerScores = self->GetVar<std::vector<int32_t>>(PlayerScoresVariable);
|
auto playerScores = self->GetVar<std::vector<int32_t>>(PlayerScoresVariable);
|
||||||
|
|
||||||
for (const auto& waveScore : playerScores) {
|
for (const auto& waveScore : playerScores) {
|
||||||
totalWaveScore += waveScore;
|
totalWaveScore -= waveScore;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentWave >= playerScores.size()) {
|
if (currentWave >= playerScores.size()) {
|
||||||
@@ -526,6 +510,7 @@ void SGCannon::RecordPlayerScore(Entity* self) {
|
|||||||
} else {
|
} else {
|
||||||
playerScores[currentWave] = totalWaveScore;
|
playerScores[currentWave] = totalWaveScore;
|
||||||
}
|
}
|
||||||
|
self->SetVar<std::vector<int32_t>>(PlayerScoresVariable, playerScores);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -547,12 +532,11 @@ void SGCannon::PlaySceneAnimation(Entity* self, const std::u16string& animationN
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SGCannon::PauseChargeCannon(Entity* self) {
|
void SGCannon::PauseChargeCannon(Entity* self) {
|
||||||
const auto time = std::max(static_cast<uint32_t>(std::ceil(ActivityTimerGetCurrentTime(self, SuperChargeTimer))), static_cast<uint32_t>(1));
|
const auto time = std::max(static_cast<uint32_t>(std::ceil(ActivityTimerGetRemainingTime(self, SuperChargeTimer))), static_cast<uint32_t>(1));
|
||||||
|
|
||||||
self->SetVar<bool>(SuperChargePausedVariable, true);
|
self->SetVar<bool>(SuperChargePausedVariable, true);
|
||||||
self->SetVar<uint32_t>(CurrentSuperChargedTimeVariable, time);
|
self->SetVar<uint32_t>(CurrentSuperChargedTimeVariable, time);
|
||||||
self->SetNetworkVar<uint32_t>(ChargeCountingVariable, time);
|
self->SetNetworkVar<uint32_t>(ChargeCountingVariable, time);
|
||||||
|
|
||||||
ActivityTimerStop(self, SuperChargeTimer);
|
ActivityTimerStop(self, SuperChargeTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -568,14 +552,17 @@ void SGCannon::StopGame(Entity* self, bool cancel) {
|
|||||||
|
|
||||||
// The player won, store all the score and send rewards
|
// The player won, store all the score and send rewards
|
||||||
if (!cancel) {
|
if (!cancel) {
|
||||||
int32_t percentage = 0.0f;
|
float percentage = 0.0f;
|
||||||
auto misses = self->GetVar<uint32_t>(MissesVariable);
|
float misses = self->GetVar<uint32_t>(MissesVariable);
|
||||||
auto fired = self->GetVar<uint32_t>(ShotsFiredVariable);
|
float fired = self->GetVar<uint32_t>(ShotsFiredVariable);
|
||||||
|
|
||||||
if (fired > 0) {
|
if (fired > 0.0f) {
|
||||||
percentage = misses / fired;
|
percentage = misses / fired;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
percentage = 1.0f - percentage;
|
||||||
|
percentage = std::max(percentage, 0.0f);
|
||||||
|
|
||||||
auto* missionComponent = player->GetComponent<MissionComponent>();
|
auto* missionComponent = player->GetComponent<MissionComponent>();
|
||||||
|
|
||||||
if (missionComponent != nullptr) {
|
if (missionComponent != nullptr) {
|
||||||
@@ -596,13 +583,27 @@ void SGCannon::StopGame(Entity* self, bool cancel) {
|
|||||||
auto* inventory = player->GetComponent<InventoryComponent>();
|
auto* inventory = player->GetComponent<InventoryComponent>();
|
||||||
if (inventory != nullptr) {
|
if (inventory != nullptr) {
|
||||||
for (const auto rewardLot : self->GetVar<std::vector<LOT>>(RewardsVariable)) {
|
for (const auto rewardLot : self->GetVar<std::vector<LOT>>(RewardsVariable)) {
|
||||||
inventory->AddItem(rewardLot, 1, eLootSourceType::ACTIVITY, eInventoryType::MODELS);
|
inventory->AddItem(rewardLot, 1, eLootSourceType::NONE, eInventoryType::MODELS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self->SetNetworkVar<std::u16string>(u"UI_Rewards",
|
const auto& waveScores = self->GetVar<std::vector<int32_t>>(PlayerScoresVariable);
|
||||||
GeneralUtils::to_u16string(self->GetVar<int32_t>(TotalScoreVariable)) + u"_0_0_0_0_0_0"
|
std::stringstream stream;
|
||||||
);
|
|
||||||
|
stream << self->GetVar<int32_t>(TotalScoreVariable) << "_";
|
||||||
|
|
||||||
|
// technically unused in shooting gallery but serialize it regardless.
|
||||||
|
for (const auto& score : waveScores) {
|
||||||
|
stream << score << "_";
|
||||||
|
}
|
||||||
|
auto totalmissed = fired - misses;
|
||||||
|
if (totalmissed < 0) {
|
||||||
|
totalmissed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream << fired << "_" << totalmissed << "_" << self->GetVar<uint32_t>(MaxStreakVariable);
|
||||||
|
|
||||||
|
self->SetNetworkVar<std::u16string>(u"UI_Rewards", GeneralUtils::ASCIIToUTF16(stream.str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
GameMessages::SendActivityStop(self->GetObjectID(), false, cancel, player->GetSystemAddress());
|
GameMessages::SendActivityStop(self->GetObjectID(), false, cancel, player->GetSystemAddress());
|
||||||
@@ -617,10 +618,42 @@ void SGCannon::StopGame(Entity* self, bool cancel) {
|
|||||||
ResetVars(self);
|
ResetVars(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SGCannon::OnActivityNotify(Entity* self, GameMessages::ActivityNotify& notify) {
|
||||||
|
if (!self->GetVar<bool>(GameStartedVariable)) return;
|
||||||
|
|
||||||
|
const auto& params = notify.notification;
|
||||||
|
if (params.empty()) return;
|
||||||
|
|
||||||
|
const auto& param = params[0];
|
||||||
|
if (param->GetValueType() != LDF_TYPE_S32 || param->GetKey() != u"shot_done") return;
|
||||||
|
|
||||||
|
const auto superChargeShotDone = static_cast<LDFData<int32_t>*>(param.get())->GetValue() == GetConstants().cannonSuperChargeSkill;
|
||||||
|
|
||||||
|
const auto& hitTargets = self->GetVar<std::vector<LWOOBJID>>(u"CannonBallKills");
|
||||||
|
|
||||||
|
if (hitTargets.empty() && !superChargeShotDone) {
|
||||||
|
self->SetVar<uint32_t>(u"m_curStreak", 0);
|
||||||
|
self->SetVar<uint32_t>(MissesVariable, self->GetVar<uint32_t>(MissesVariable) + 1);
|
||||||
|
self->SetNetworkVar<bool>(u"HideStreak", true);
|
||||||
|
self->SetNetworkVar<bool>(u"UnMarkAll", true);
|
||||||
|
UpdateStreak(self);
|
||||||
|
} else if (hitTargets.size() > 1) {
|
||||||
|
self->SetNetworkVar<bool>(u"mHit", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
self->SetVar<std::vector<LWOOBJID>>(u"CannonBallKills", {});
|
||||||
|
}
|
||||||
|
|
||||||
void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& timerName) {
|
void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& timerName) {
|
||||||
|
if (!self->GetVar<bool>(GameStartedVariable)) return;
|
||||||
|
|
||||||
|
auto cannonBallKills = self->GetVar<std::vector<LWOOBJID>>(u"CannonBallKills");
|
||||||
|
cannonBallKills.push_back(target->GetObjectID());
|
||||||
|
self->SetVar<std::vector<LWOOBJID>>(u"CannonBallKills", cannonBallKills);
|
||||||
const auto& spawnInfo = target->GetVar<SGEnemy>(u"SpawnData");
|
const auto& spawnInfo = target->GetVar<SGEnemy>(u"SpawnData");
|
||||||
|
|
||||||
if (spawnInfo.respawns) {
|
if (spawnInfo.respawns && target->GetVar<uint32_t>(u"wave") == self->GetVar<uint32_t>(ThisWaveVariable)) {
|
||||||
const auto respawnTime = GeneralUtils::GenerateRandomNumber<float_t>(spawnInfo.minRespawnTime, spawnInfo.maxRespawnTime);
|
const auto respawnTime = GeneralUtils::GenerateRandomNumber<float_t>(spawnInfo.minRespawnTime, spawnInfo.maxRespawnTime);
|
||||||
|
|
||||||
ActivityTimerStart(self, timerName, respawnTime, respawnTime);
|
ActivityTimerStart(self, timerName, respawnTime, respawnTime);
|
||||||
@@ -637,6 +670,7 @@ void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& time
|
|||||||
} else {
|
} else {
|
||||||
if (!self->GetVar<bool>(SuperChargeActiveVariable)) {
|
if (!self->GetVar<bool>(SuperChargeActiveVariable)) {
|
||||||
self->SetVar<uint32_t>(u"m_curStreak", 0);
|
self->SetVar<uint32_t>(u"m_curStreak", 0);
|
||||||
|
self->SetVar<uint32_t>(MissesVariable, self->GetVar<uint32_t>(MissesVariable) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
self->SetNetworkVar<bool>(u"hitFriend", true);
|
self->SetNetworkVar<bool>(u"hitFriend", true);
|
||||||
@@ -646,10 +680,6 @@ void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& time
|
|||||||
|
|
||||||
auto scScore = self->GetVar<int32_t>(TotalScoreVariable) - lastSuperTotal;
|
auto scScore = self->GetVar<int32_t>(TotalScoreVariable) - lastSuperTotal;
|
||||||
|
|
||||||
LOG("LastSuperTotal: %i, scScore: %i, constants.chargedPoints: %i",
|
|
||||||
lastSuperTotal, scScore, constants.chargedPoints
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!self->GetVar<bool>(SuperChargeActiveVariable) && scScore >= constants.chargedPoints && score >= 0) {
|
if (!self->GetVar<bool>(SuperChargeActiveVariable) && scScore >= constants.chargedPoints && score >= 0) {
|
||||||
StartChargedCannon(self);
|
StartChargedCannon(self);
|
||||||
self->SetNetworkVar<float>(u"SuperChargeBar", 100.0f);
|
self->SetNetworkVar<float>(u"SuperChargeBar", 100.0f);
|
||||||
@@ -684,6 +714,40 @@ void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& time
|
|||||||
if (missionComponent == nullptr) return;
|
if (missionComponent == nullptr) return;
|
||||||
|
|
||||||
missionComponent->Progress(eMissionTaskType::SMASH, spawnInfo.lot, self->GetObjectID());
|
missionComponent->Progress(eMissionTaskType::SMASH, spawnInfo.lot, self->GetObjectID());
|
||||||
|
|
||||||
|
auto matrix = self->GetVar<uint32_t>(MatrixVariable);
|
||||||
|
|
||||||
|
float rewardS = 0.0f;
|
||||||
|
float rewardF = 0.0f;
|
||||||
|
if (matrix <= 5) {
|
||||||
|
const auto scoreRewardNum = "Score_Reward_" + std::to_string(matrix);
|
||||||
|
const auto rewardAmountItr = constants.scoreRewards.find(scoreRewardNum);
|
||||||
|
if (rewardAmountItr != constants.scoreRewards.end()) {
|
||||||
|
const float rewardAmount = rewardAmountItr->second / 100 * 3;
|
||||||
|
rewardS = newScore / rewardAmount;
|
||||||
|
rewardF = std::round(rewardS * 3);
|
||||||
|
|
||||||
|
if (rewardF > 100.0f) rewardF = 100.0f;
|
||||||
|
|
||||||
|
self->SetNetworkVar(ModelPercentVariable, rewardF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rewardF > 0.0f && rewardF < 200.0f && matrix <= 5) {
|
||||||
|
const auto rewardModelGroup = Game::entityManager->GetEntitiesInGroup(constants.rewardModelGroup);
|
||||||
|
if (!rewardModelGroup.empty()) {
|
||||||
|
auto* rewardModel = rewardModelGroup[0];
|
||||||
|
GameMessages::SpawnModelBricks spawnBricks{};
|
||||||
|
spawnBricks.target = rewardModel->GetObjectID();
|
||||||
|
spawnBricks.amount = rewardF / 100.0f;
|
||||||
|
spawnBricks.position = target->GetPosition();
|
||||||
|
spawnBricks.Send(player->GetSystemAddress());
|
||||||
|
if (rewardF >= 100.0f) {
|
||||||
|
SpawnNewModel(self);
|
||||||
|
self->SetVar<uint32_t>(MatrixVariable, matrix + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SGCannon::UpdateStreak(Entity* self) {
|
void SGCannon::UpdateStreak(Entity* self) {
|
||||||
@@ -745,41 +809,34 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) {
|
|||||||
|
|
||||||
auto* selfInventoryComponent = self->GetComponent<InventoryComponent>();
|
auto* selfInventoryComponent = self->GetComponent<InventoryComponent>();
|
||||||
|
|
||||||
if (inventoryComponent == nullptr) {
|
// This is a gm in the original script
|
||||||
LOG("Inventory component not found");
|
Item* meItem1{};
|
||||||
|
Item* meItem2{};
|
||||||
|
for (const auto item : selfInventoryComponent->GetInventory(eInventoryType::ITEMS)->GetItems() | std::views::values) {
|
||||||
|
if (item->GetSlot() == 0) meItem1 = item;
|
||||||
|
else if (item->GetSlot() == 1) meItem2 = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!meItem1 || !meItem2) {
|
||||||
|
LOG("Cannon does not have the required items equipped");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enable) {
|
if (enable) {
|
||||||
LOG("Player is activating super charge");
|
LOG("Player is activating super charge");
|
||||||
selfInventoryComponent->UpdateSlot("greeble_r", { ObjectIDManager::GenerateRandomObjectID(), 6505, 1, 0 });
|
selfInventoryComponent->EquipItem(meItem1);
|
||||||
selfInventoryComponent->UpdateSlot("greeble_l", { ObjectIDManager::GenerateRandomObjectID(), 6506, 1, 0 });
|
selfInventoryComponent->EquipItem(meItem2);
|
||||||
|
|
||||||
// TODO: Equip items
|
|
||||||
skillID = constants.cannonSuperChargeSkill;
|
skillID = constants.cannonSuperChargeSkill;
|
||||||
cooldown = 400;
|
cooldown = 400;
|
||||||
} else {
|
} else {
|
||||||
selfInventoryComponent->UpdateSlot("greeble_r", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 });
|
selfInventoryComponent->UnEquipItem(meItem1);
|
||||||
selfInventoryComponent->UpdateSlot("greeble_l", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 });
|
selfInventoryComponent->UnEquipItem(meItem2);
|
||||||
|
|
||||||
self->SetNetworkVar<float>(u"SuperChargeBar", 0);
|
self->SetNetworkVar<float>(u"SuperChargeBar", 0);
|
||||||
|
|
||||||
LOG("Player disables super charge");
|
LOG("Player disables super charge");
|
||||||
|
|
||||||
// TODO: Unequip items
|
|
||||||
for (const auto& equipped : equippedItems) {
|
|
||||||
if (equipped.first == "special_r" || equipped.first == "special_l") {
|
|
||||||
LOG("Trying to unequip a weapon, %i", equipped.second.lot);
|
|
||||||
|
|
||||||
auto* item = inventoryComponent->FindItemById(equipped.second.id);
|
|
||||||
|
|
||||||
if (item != nullptr) {
|
|
||||||
inventoryComponent->UnEquipItem(item);
|
|
||||||
} else {
|
|
||||||
LOG("Item not found, %i", equipped.second.lot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cooldown = 800;
|
cooldown = 800;
|
||||||
self->SetVar<uint32_t>(NumberOfChargesVariable, 0);
|
self->SetVar<uint32_t>(NumberOfChargesVariable, 0);
|
||||||
}
|
}
|
||||||
@@ -794,10 +851,10 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) {
|
|||||||
|
|
||||||
DynamicShootingGalleryParams properties = shootingGalleryComponent->GetDynamicParams();
|
DynamicShootingGalleryParams properties = shootingGalleryComponent->GetDynamicParams();
|
||||||
|
|
||||||
properties.cannonFOV = 58.6f;
|
properties.cannonFOV = constants.cannonFOV;
|
||||||
properties.cannonVelocity = 129.0;
|
properties.cannonVelocity = constants.cannonVelocity;
|
||||||
properties.cannonRefireRate = cooldown;
|
properties.cannonRefireRate = cooldown;
|
||||||
properties.cannonMinDistance = 30;
|
properties.cannonMinDistance = constants.cannonMinDistance;
|
||||||
properties.cannonTimeout = -1;
|
properties.cannonTimeout = -1;
|
||||||
|
|
||||||
shootingGalleryComponent->SetDynamicParams(properties);
|
shootingGalleryComponent->SetDynamicParams(properties);
|
||||||
@@ -829,22 +886,38 @@ std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() {
|
|||||||
1.0, false, true
|
1.0, false, true
|
||||||
},
|
},
|
||||||
|
|
||||||
// Sub 1
|
// Sub 1 but for dlu
|
||||||
{
|
{
|
||||||
std::vector<std::string> { "Wave_1_Sub_1", "Wave_1_Sub_2" },
|
std::vector<std::string> { "Wave_1_Sub_1", "Wave_1_Sub_2" },
|
||||||
6016, 0.0, 2.0, true, 0.0, 2.0,
|
6016, 0.0, 2.0, true, 0.0, 2.0,
|
||||||
10.0, 1000, false, 0.0, 1.0,
|
|
||||||
1.0, true, true
|
|
||||||
},
|
|
||||||
|
|
||||||
// Sub 2
|
|
||||||
{
|
|
||||||
std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" },
|
|
||||||
6016, 0.0, 2.0, true, 0.0, 2.0,
|
|
||||||
2.0, 1000, false, 0.0, 1.0,
|
2.0, 1000, false, 0.0, 1.0,
|
||||||
1.0, true, true
|
1.0, true, true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
//// Sub 1
|
||||||
|
//{
|
||||||
|
// std::vector<std::string> { "Wave_1_Sub_1", "Wave_1_Sub_2" },
|
||||||
|
// 6016, 0.0, 2.0, true, 0.0, 2.0,
|
||||||
|
// 10.0, 1000, false, 0.0, 1.0,
|
||||||
|
// 1.0, true, true
|
||||||
|
//},
|
||||||
|
|
||||||
|
// Sub 2 but for dlu
|
||||||
|
{
|
||||||
|
std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" },
|
||||||
|
6016, 0.0, 2.0, true, 0.0, 2.0,
|
||||||
|
3.0, 1000, false, 0.0, 1.0,
|
||||||
|
1.0, true, true
|
||||||
|
},
|
||||||
|
|
||||||
|
// Sub 2
|
||||||
|
//{
|
||||||
|
// std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" },
|
||||||
|
// 6016, 0.0, 2.0, true, 0.0, 2.0,
|
||||||
|
// 2.0, 1000, false, 0.0, 1.0,
|
||||||
|
// 1.0, true, true
|
||||||
|
//},
|
||||||
|
|
||||||
// Friendly
|
// Friendly
|
||||||
{
|
{
|
||||||
std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" },
|
std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" },
|
||||||
@@ -897,10 +970,18 @@ std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// Sub 2
|
// Sub 2
|
||||||
|
//{
|
||||||
|
// std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" },
|
||||||
|
// 6016, 0.0, 2.0, true, 0.0, 2.0,
|
||||||
|
// 2.0, 1000, false, 0.0, 1.0,
|
||||||
|
// 1.0, true, true
|
||||||
|
//},
|
||||||
|
|
||||||
|
// Sub 2 but for dlu
|
||||||
{
|
{
|
||||||
std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" },
|
std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" },
|
||||||
6016, 0.0, 2.0, true, 0.0, 2.0,
|
6016, 0.0, 2.0, true, 0.0, 2.0,
|
||||||
2.0, 1000, false, 0.0, 1.0,
|
3.0, 1000, false, 0.0, 1.0,
|
||||||
1.0, true, true
|
1.0, true, true
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -963,11 +1044,19 @@ std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() {
|
|||||||
1.0, true, true
|
1.0, true, true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Sub 2
|
||||||
|
//{
|
||||||
|
// std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" },
|
||||||
|
// 6016, 0.0, 2.0, true, 0.0, 2.0,
|
||||||
|
// 2.0, 1000, false, 0.0, 1.0,
|
||||||
|
// 1.0, true, true
|
||||||
|
//},
|
||||||
|
|
||||||
// Sub 2
|
// Sub 2
|
||||||
{
|
{
|
||||||
std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" },
|
std::vector<std::string> { "Wave_2_Sub_1", "Wave_2_Sub_2" },
|
||||||
6016, 0.0, 2.0, true, 0.0, 2.0,
|
6016, 0.0, 2.0, true, 0.0, 2.0,
|
||||||
2.0, 1000, false, 0.0, 1.0,
|
3.0, 1000, false, 0.0, 1.0,
|
||||||
1.0, true, true
|
1.0, true, true
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -987,14 +1076,22 @@ std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() {
|
|||||||
1.0, false, true
|
1.0, false, true
|
||||||
},
|
},
|
||||||
|
|
||||||
// Ness
|
// Ness temp fix for dlu where speeds are set to 7 to match a speed closer to live while we work on movingplatform components.
|
||||||
{
|
{
|
||||||
std::vector<std::string> { "Wave_1_Ness_1", "Wave_1_Ness_2", "Wave_2_Ness_1" },
|
std::vector<std::string> { "Wave_1_Ness_1", "Wave_1_Ness_2", "Wave_2_Ness_1" },
|
||||||
2565, 10.0, 15.0, true, 10.0, 15.0,
|
2565, 10.0, 15.0, true, 10.0, 15.0,
|
||||||
2.0, 10000, false, 0.0, 1.0,
|
7.0, 10000, false, 0.0, 7.0,
|
||||||
1.0, true, true
|
7.0, true, true
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// // Ness
|
||||||
|
// {
|
||||||
|
// std::vector<std::string> { "Wave_1_Ness_1", "Wave_1_Ness_2", "Wave_2_Ness_1" },
|
||||||
|
// 2565, 10.0, 15.0, true, 10.0, 15.0,
|
||||||
|
// 2.0, 10000, false, 0.0, 1.0,
|
||||||
|
// 1.0, true, true
|
||||||
|
// },
|
||||||
|
|
||||||
// Friendly 1
|
// Friendly 1
|
||||||
{
|
{
|
||||||
std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" },
|
std::vector<std::string> { "Wave_3_FShip_1", "Wave_3_FShip_2" },
|
||||||
@@ -1033,11 +1130,8 @@ void SGCannon::ResetVars(Entity* self) {
|
|||||||
self->SetVar<int32_t>(TotalScoreVariable, 0);
|
self->SetVar<int32_t>(TotalScoreVariable, 0);
|
||||||
|
|
||||||
self->SetVar<uint32_t>(u"m_curStreak", 0);
|
self->SetVar<uint32_t>(u"m_curStreak", 0);
|
||||||
self->SetNetworkVar<float>(u"SuperChargeBar", 0);
|
|
||||||
self->SetVar<uint32_t>(u"LastSuperTotal", 0);
|
self->SetVar<uint32_t>(u"LastSuperTotal", 0);
|
||||||
self->SetNetworkVar<float>(u"SuperChargeBar", 0.0f);
|
self->SetVar<std::vector<LWOOBJID>>(u"LastHitTarget", {});
|
||||||
self->SetNetworkVar<bool>(u"ShowStreak", 0);
|
|
||||||
self->SetNetworkVar<bool>(u"UnMarkAll", true);
|
|
||||||
|
|
||||||
const_cast<std::vector<SGEnemy>&>(self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable)).clear();
|
const_cast<std::vector<SGEnemy>&>(self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable)).clear();
|
||||||
self->SetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable, {});
|
self->SetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable, {});
|
||||||
@@ -1056,40 +1150,42 @@ void SGCannon::ResetVars(Entity* self) {
|
|||||||
|
|
||||||
SGConstants SGCannon::GetConstants() {
|
SGConstants SGCannon::GetConstants() {
|
||||||
return {
|
return {
|
||||||
Vector3 { -908.542480, 229.773178, -908.542480 },
|
.playerStartPosition = Vector3 { -908.542480, 229.773178, -908.542480 },
|
||||||
Quaternion { 0.91913521289825, 0, 0.39394217729568, 0 },
|
.playerStartRotation = Quaternion { 0.91913521289825, 0, 0.39394217729568, 0 },
|
||||||
1864,
|
.cannonLot = 1864,
|
||||||
34,
|
.impactSkillID = 34,
|
||||||
1822,
|
.projectileLot = 1822,
|
||||||
Vector3 { 6.652, -2, 1.5 },
|
.playerOffset = Vector3 { 6.652, -2, 1.5 },
|
||||||
157,
|
.rewardModelMatrix = 157,
|
||||||
129.0,
|
.cannonVelocity = 129.0,
|
||||||
30.0,
|
.cannonMinDistance = 30.0,
|
||||||
800.0,
|
.cannonRefireRate = 800.0,
|
||||||
Vector3 { 0, 4.3, 9 },
|
.cannonBarrelOffset = Vector3 { 0, 4.3, 9 },
|
||||||
6297,
|
.cannonSuperchargedProjectileLot = 6297,
|
||||||
1822,
|
.cannonProjectileLot = 1822,
|
||||||
249,
|
.cannonSuperChargeSkill = 249,
|
||||||
228,
|
.cannonSkill = 228,
|
||||||
-1,
|
.cannonTimeout = -1,
|
||||||
58.6,
|
.cannonFOV = 58.6,
|
||||||
true,
|
.useLeaderboards = true,
|
||||||
2,
|
.streakModifier = 2,
|
||||||
10,
|
.chargedTime = 10,
|
||||||
25000,
|
.chargedPoints = 25000,
|
||||||
"QBRewardGroup",
|
.rewardModelGroup = "QBRewardGroup",
|
||||||
1864,
|
.activityID = 1864,
|
||||||
50000,
|
.scoreRewards = {
|
||||||
157,
|
{"Score_Reward_1", 50000},
|
||||||
100000,
|
{"Score_Reward_2", 100000},
|
||||||
187,
|
{"Score_Reward_3", 200000},
|
||||||
200000,
|
{"Score_Reward_4", 400000},
|
||||||
188,
|
{"Score_Reward_5", 800000},
|
||||||
400000,
|
},
|
||||||
189,
|
.scoreLootMatrix1 = 157,
|
||||||
800000,
|
.scoreLootMatrix2 = 187,
|
||||||
190,
|
.scoreLootMatrix3 = 188,
|
||||||
4.0,
|
.scoreLootMatrix4 = 189,
|
||||||
7.0
|
.scoreLootMatrix5 = 190,
|
||||||
|
.firstWaveStartTime = 4.0,
|
||||||
|
.inBetweenWavePause = 7.0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,15 +44,11 @@ struct SGConstants {
|
|||||||
uint32_t chargedPoints;
|
uint32_t chargedPoints;
|
||||||
std::string rewardModelGroup;
|
std::string rewardModelGroup;
|
||||||
uint32_t activityID;
|
uint32_t activityID;
|
||||||
uint32_t scoreReward1;
|
std::map<std::string, uint32_t> scoreRewards;
|
||||||
uint32_t scoreLootMatrix1;
|
uint32_t scoreLootMatrix1;
|
||||||
uint32_t scoreReward2;
|
|
||||||
uint32_t scoreLootMatrix2;
|
uint32_t scoreLootMatrix2;
|
||||||
uint32_t scoreReward3;
|
|
||||||
uint32_t scoreLootMatrix3;
|
uint32_t scoreLootMatrix3;
|
||||||
uint32_t scoreReward4;
|
|
||||||
uint32_t scoreLootMatrix4;
|
uint32_t scoreLootMatrix4;
|
||||||
uint32_t scoreReward5;
|
|
||||||
uint32_t scoreLootMatrix5;
|
uint32_t scoreLootMatrix5;
|
||||||
float_t firstWaveStartTime;
|
float_t firstWaveStartTime;
|
||||||
float_t inBetweenWavePause;
|
float_t inBetweenWavePause;
|
||||||
@@ -68,6 +64,8 @@ public:
|
|||||||
void OnActivityTimerDone(Entity* self, const std::string& name) override;
|
void OnActivityTimerDone(Entity* self, const std::string& name) override;
|
||||||
void OnActivityTimerUpdate(Entity* self, const std::string& name, float_t timeRemaining, float_t elapsedTime) override;
|
void OnActivityTimerUpdate(Entity* self, const std::string& name, float_t timeRemaining, float_t elapsedTime) override;
|
||||||
void OnRequestActivityExit(Entity* self, LWOOBJID player, bool canceled) override;
|
void OnRequestActivityExit(Entity* self, LWOOBJID player, bool canceled) override;
|
||||||
|
void OnActivityNotify(Entity* self, GameMessages::ActivityNotify& notify) override;
|
||||||
|
void OnShootingGalleryFire(Entity& self, GameMessages::ShootingGalleryFire& fire) override;
|
||||||
void SuperChargeTimerFunc(Entity* self);
|
void SuperChargeTimerFunc(Entity* self);
|
||||||
void SpawnWaveTimerFunc(Entity* self);
|
void SpawnWaveTimerFunc(Entity* self);
|
||||||
void EndWaveTimerFunc(Entity* self);
|
void EndWaveTimerFunc(Entity* self);
|
||||||
@@ -142,6 +140,7 @@ private:
|
|||||||
std::u16string CannonBallSkillIDVariable = u"cbskill";
|
std::u16string CannonBallSkillIDVariable = u"cbskill";
|
||||||
std::u16string HideSuperChargeVariable = u"HideSuper";
|
std::u16string HideSuperChargeVariable = u"HideSuper";
|
||||||
std::u16string AudioFinalWaveDoneVariable = u"Audio_Final_Wave_Done";
|
std::u16string AudioFinalWaveDoneVariable = u"Audio_Final_Wave_Done";
|
||||||
|
std::u16string ModelPercentVariable = u"modelPercent";
|
||||||
|
|
||||||
std::string SpawnWaveTimer = "SpawnWave";
|
std::string SpawnWaveTimer = "SpawnWave";
|
||||||
std::string EndWaveTimer = "EndWave";
|
std::string EndWaveTimer = "EndWave";
|
||||||
|
|||||||
@@ -1386,7 +1386,9 @@ void HandlePacket(Packet* packet) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
const auto messageId = *reinterpret_cast<MessageType::World*>(&packet->data[3]);
|
// Need to use FromBitsUnchecked (aka memcpy) instead of reinterpret_cast to avoid misaligned reads, which are UB
|
||||||
|
const auto messageId = GeneralUtils::FromBitsUnchecked<MessageType::World>(&packet->data[3]);
|
||||||
|
|
||||||
const std::string_view messageIdString = StringifiedEnum::ToString(messageId);
|
const std::string_view messageIdString = StringifiedEnum::ToString(messageId);
|
||||||
LOG("Unknown world packet received: %4i, %s", messageId, messageIdString.data());
|
LOG("Unknown world packet received: %4i, %s", messageId, messageIdString.data());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ TEST(dCommonTests, AMF3InsertionAssociativeTest) {
|
|||||||
array.Insert<std::vector<uint32_t>>("Undefined", {});
|
array.Insert<std::vector<uint32_t>>("Undefined", {});
|
||||||
array.Insert("Null", nullptr);
|
array.Insert("Null", nullptr);
|
||||||
|
|
||||||
ASSERT_EQ(array.Get<const char*>("CString")->GetValueType(), eAmf::String);
|
ASSERT_EQ(array.Get("CString")->GetValueType(), eAmf::String);
|
||||||
ASSERT_EQ(array.Get<std::string>("String")->GetValueType(), eAmf::String);
|
ASSERT_EQ(array.Get<std::string>("String")->GetValueType(), eAmf::String);
|
||||||
ASSERT_EQ(array.Get<bool>("False")->GetValueType(), eAmf::False);
|
ASSERT_EQ(array.Get<bool>("False")->GetValueType(), eAmf::False);
|
||||||
ASSERT_EQ(array.Get<bool>("True")->GetValueType(), eAmf::True);
|
ASSERT_EQ(array.Get<bool>("True")->GetValueType(), eAmf::True);
|
||||||
@@ -95,7 +95,7 @@ TEST(dCommonTests, AMF3InsertionDenseTest) {
|
|||||||
array.Push<std::vector<uint32_t>>({});
|
array.Push<std::vector<uint32_t>>({});
|
||||||
|
|
||||||
ASSERT_EQ(array.Get<std::string>(0)->GetValueType(), eAmf::String);
|
ASSERT_EQ(array.Get<std::string>(0)->GetValueType(), eAmf::String);
|
||||||
ASSERT_EQ(array.Get<const char*>(1)->GetValueType(), eAmf::String);
|
ASSERT_EQ(array.Get(1)->GetValueType(), eAmf::String);
|
||||||
ASSERT_EQ(array.Get<bool>(2)->GetValueType(), eAmf::False);
|
ASSERT_EQ(array.Get<bool>(2)->GetValueType(), eAmf::False);
|
||||||
ASSERT_EQ(array.Get<bool>(3)->GetValueType(), eAmf::True);
|
ASSERT_EQ(array.Get<bool>(3)->GetValueType(), eAmf::True);
|
||||||
ASSERT_EQ(array.Get<int32_t>(4)->GetValueType(), eAmf::Integer);
|
ASSERT_EQ(array.Get<int32_t>(4)->GetValueType(), eAmf::Integer);
|
||||||
|
|||||||
1
valgrind.sh
Normal file
1
valgrind.sh
Normal file
@@ -0,0 +1 @@
|
|||||||
|
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --verbose --log-file=valgrind-out.txt build/gnu-debug/MasterServer
|
||||||
Reference in New Issue
Block a user