mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2025-12-20 11:59:40 -06:00
Compare commits
24 Commits
v3.0.1
...
quickbuild
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0913ff23d | ||
|
|
b738504812 | ||
|
|
c968dc9028 | ||
|
|
2209a4432f | ||
|
|
c855a6b9cf | ||
|
|
8abc545bd1 | ||
|
|
136133dde2 | ||
|
|
23551d4ed8 | ||
|
|
7599a2e81e | ||
| a6c6d892cf | |||
|
|
fb32534ae3 | ||
|
|
c8fcb3788d | ||
|
|
86b419735b | ||
|
|
9936bb0d00 | ||
|
|
beffad42ea | ||
|
|
3ecbd1013b | ||
|
|
ff4546c027 | ||
|
|
71baa5ce90 | ||
|
|
5ccd15a7d8 | ||
|
|
35bcaf6e95 | ||
|
|
900c9b6abe | ||
|
|
94e7cfc211 | ||
|
|
021db0ecd1 | ||
|
|
0b261e934f |
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "thirdparty/cpp-httplib"]
|
||||
path = thirdparty/cpp-httplib
|
||||
url = https://github.com/yhirose/cpp-httplib
|
||||
[submodule "thirdparty/tinyxml2"]
|
||||
path = thirdparty/tinyxml2
|
||||
url = https://github.com/leethomason/tinyxml2
|
||||
|
||||
@@ -247,7 +247,6 @@ include_directories(
|
||||
"thirdparty/recastnavigation"
|
||||
"thirdparty/SQLite"
|
||||
"thirdparty/cpplinq"
|
||||
"thirdparty/cpp-httplib"
|
||||
"thirdparty/MD5"
|
||||
)
|
||||
|
||||
|
||||
54
README.md
54
README.md
@@ -32,6 +32,8 @@ Darkflame Universe is a server emulator and does not distribute any LEGO® Unive
|
||||
* To connect to the server, either delete the file `boot.cfg` which is found in your LEGO Universe client, rename the file `boot.cfg` to something else or follow the steps [here](#allowing-a-user-to-connect-to-your-server) if you wish to keep the file.
|
||||
* When shutting down the server, it is highly recommended to click the `MasterServer.exe` window and hold `ctrl` while pressing `c` to stop the server.
|
||||
* We are working on a way to make it so when you close the game, the server stops automatically alongside when you open the game, the server starts automatically.
|
||||
* If you are not setting a server up on mac, you can ignore this note
|
||||
* Note: you'll need to allow through System Preferences `AuthServer`, `ChatServer`, `MasterServer`, `WorldServer` and `libmariadbcpp.dylib` to run. The initial pop-up will block it due to the binaries being unsigned, after allowing them to run the servers will run as normal.
|
||||
|
||||
<font size="32">**If you are not planning on hosting a server for others, working in the codebase or wanting to use MariaDB for a database, you can stop reading here.**</font>
|
||||
|
||||
@@ -68,6 +70,12 @@ git clone --recursive https://github.com/DarkflameUniverse/DarkflameServer
|
||||
|
||||
## Install dependencies
|
||||
|
||||
### Required compiler versions
|
||||
- g++11 or greater
|
||||
- MSVC unchecked
|
||||
- clang unchecked
|
||||
- appleclang unchecked
|
||||
|
||||
### Windows packages
|
||||
Ensure that you have either the [MSVC C++ compiler](https://visualstudio.microsoft.com/vs/features/cplusplus/) (recommended) or the [Clang compiler](https://github.com/llvm/llvm-project/releases/) installed.
|
||||
You'll also need to download and install [CMake](https://cmake.org/download/) (version <font size="4">**CMake version 3.25**</font> or later!).
|
||||
@@ -202,6 +210,7 @@ If you would like to build the server faster, append `-j<number>` where number i
|
||||
### Notes
|
||||
Depending on your operating system, you may need to adjust some pre-processor defines in [CMakeVariables.txt](./CMakeVariables.txt) before building:
|
||||
* If you are on MacOS, ensure OPENSSL_ROOT_DIR is pointing to the openssl root directory.
|
||||
* By default it should be set to the correct directory.
|
||||
* If you are using a Darkflame Universe client, ensure `client_net_version` in `build/sharedconfig.ini` is changed to 171023.
|
||||
|
||||
## Configuring your server
|
||||
@@ -224,28 +233,41 @@ Navigate to `build/sharedconfig.ini` and fill in the following fields:
|
||||
* `chatconfig.ini` contains a port option.
|
||||
* `masterconfig.ini` contains options related to permissions you want to run your servers with.
|
||||
* `sharedconfig.ini` contains several options that are shared across all servers
|
||||
* `worldconfig.ini` contains several options to turn on QOL improvements should you want them. If you would like the most vanilla experience possible, you will need to turn some of these settings off.
|
||||
* `worldconfig.ini` contains several options to turn on Quality of Life improvements should you want them. If you would like the most vanilla experience possible, you will need to turn some of these settings off.
|
||||
|
||||
## Verify your setup
|
||||
Your build directory should now look like this:
|
||||
* AuthServer
|
||||
* ChatServer
|
||||
* MasterServer
|
||||
* WorldServer
|
||||
* authconfig.ini
|
||||
* chatconfig.ini
|
||||
* masterconfig.ini
|
||||
Your build directory should contain at a minimum all of the following files.
|
||||
All listed files are required for a server to start.
|
||||
`ini` files can be located at the environment variable `DLU_CONFIG_DIR` and do not need to be located in this directory.
|
||||
(windows will have .exe at the end of the executables):
|
||||
* sharedconfig.ini
|
||||
* AuthServer(.exe)
|
||||
* authconfig.ini
|
||||
* ChatServer(.exe)
|
||||
* chatconfig.ini
|
||||
* MasterServer(.exe)
|
||||
* masterconfig.ini
|
||||
* WorldServer(.exe)
|
||||
* worldconfig.ini
|
||||
* ...
|
||||
* blocklist.dcf
|
||||
* migrations
|
||||
* vanity
|
||||
* navmeshes
|
||||
* 1 of the following lists based on platform
|
||||
* windows
|
||||
* libmariadb.dll
|
||||
* mariadbcpp.dll
|
||||
* zlib.dll
|
||||
* MacOS
|
||||
* libmariadbcpp.dylib
|
||||
* *nix
|
||||
* libmariadbcpp.so
|
||||
|
||||
## Running the server
|
||||
If everything has been configured correctly you should now be able to run the `MasterServer` binary which is located in the `build` directory. Darkflame Universe utilizes port numbers under 1024, so under Linux you either have to give the `AuthServer` binary network permissions or run it under sudo.
|
||||
To give `AuthServer` network permissions and not require sudo, run the following command
|
||||
If everything has been configured correctly you should now be able to run the `MasterServer` binary which is located in the `build` directory. Darkflame Universe utilizes port numbers under 1024, so under Linux you have to give the `AuthServer` binary network permissions by running the following command:
|
||||
```bash
|
||||
sudo setcap 'cap_net_bind_service=+ep' AuthServer
|
||||
```
|
||||
and then go to `build/masterconfig.ini` and change `use_sudo_auth` to 0.
|
||||
|
||||
### Linux Service
|
||||
If you are running this on a linux based system, it will use your terminal to run the program interactively, preventing you using it for other tasks and requiring it to be open to run the server.
|
||||
@@ -308,8 +330,14 @@ To connect to a server follow these steps:
|
||||
* Replace the contents after to `:` and the following `,` with what you configured as the server's public facing IP. For example `AUTHSERVERIP=0:localhost` for locally hosted servers
|
||||
* Next locate the line `UGCUSE3DSERVICES=7:`
|
||||
* Ensure the number after the 7 is a `0`
|
||||
* Alternatively, remove the line with `UGCUSE3DSERVICES` altogether
|
||||
* Launch `legouniverse.exe`, through `wine` if on a Unix-like operating system
|
||||
* Note that if you are on WSL2, you will need to configure the public IP in the server and client to be the IP of the WSL2 instance and not localhost, which can be found by running `ifconfig` in the terminal. Windows defaults to WSL1, so this will not apply to most users.
|
||||
As an example, here is what the boot.cfg is required to contain for a server with the ip 12.34.56.78
|
||||
```cfg
|
||||
AUTHSERVERIP=0:12.34.56.78,
|
||||
UGCUSE3DSERVICES=7:0
|
||||
```
|
||||
|
||||
## Updating your server
|
||||
To update your server to the latest version navigate to your cloned directory
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "Game.h"
|
||||
#include "Server.h"
|
||||
|
||||
|
||||
namespace Game {
|
||||
Logger* logger = nullptr;
|
||||
dServer* server = nullptr;
|
||||
@@ -71,12 +70,15 @@ int main(int argc, char** argv) {
|
||||
//Find out the master's IP:
|
||||
std::string masterIP;
|
||||
uint32_t masterPort = 1500;
|
||||
std::string masterPassword;
|
||||
|
||||
auto masterInfo = Database::Get()->GetMasterInfo();
|
||||
if (masterInfo) {
|
||||
masterIP = masterInfo->ip;
|
||||
masterPort = masterInfo->port;
|
||||
masterPassword = masterInfo->password;
|
||||
}
|
||||
|
||||
LOG("Master is at %s:%d", masterIP.c_str(), masterPort);
|
||||
|
||||
Game::randomEngine = std::mt19937(time(0));
|
||||
@@ -90,7 +92,7 @@ int main(int argc, char** argv) {
|
||||
const auto externalIPString = Game::config->GetValue("external_ip");
|
||||
if (!externalIPString.empty()) ourIP = externalIPString;
|
||||
|
||||
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::lastSignal);
|
||||
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, &Game::lastSignal, masterPassword);
|
||||
|
||||
//Run it until server gets a kill message from Master:
|
||||
auto t = std::chrono::high_resolution_clock::now();
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
add_executable(AuthServer "AuthServer.cpp")
|
||||
|
||||
target_link_libraries(AuthServer ${COMMON_LIBRARIES} dServer)
|
||||
|
||||
target_include_directories(AuthServer PRIVATE ${PROJECT_SOURCE_DIR}/dServer)
|
||||
|
||||
add_compile_definitions(AuthServer PRIVATE PROJECT_VERSION="\"${PROJECT_VERSION}\"")
|
||||
|
||||
@@ -49,7 +49,7 @@ void ChatPacketHandler::HandleFriendlistRequest(Packet* packet) {
|
||||
fd.zoneID = fr.zoneID;
|
||||
|
||||
//Since this friend is online, we need to update them on the fact that we've just logged in:
|
||||
SendFriendUpdate(fr, player, 1, fd.isBestFriend);
|
||||
if (player.isLogin) SendFriendUpdate(fr, player, 1, fd.isBestFriend);
|
||||
} else {
|
||||
fd.isOnline = false;
|
||||
fd.zoneID = LWOZONEID();
|
||||
@@ -103,7 +103,8 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
return;
|
||||
};
|
||||
|
||||
auto& requestee = Game::playerContainer.GetPlayerDataMutable(playerName);
|
||||
// Intentional copy
|
||||
PlayerData requestee = Game::playerContainer.GetPlayerData(playerName);
|
||||
|
||||
// Check if player is online first
|
||||
if (isBestFriendRequest && !requestee) {
|
||||
@@ -140,7 +141,7 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
|
||||
// Prevent GM friend spam
|
||||
// If the player we are trying to be friends with is not a civilian and we are a civilian, abort the process
|
||||
if (requestee.gmLevel > eGameMasterLevel::CIVILIAN && requestor.gmLevel == eGameMasterLevel::CIVILIAN ) {
|
||||
if (requestee.gmLevel > eGameMasterLevel::CIVILIAN && requestor.gmLevel == eGameMasterLevel::CIVILIAN) {
|
||||
SendFriendResponse(requestor, requestee, eAddFriendResponseType::MYTHRAN);
|
||||
return;
|
||||
}
|
||||
@@ -188,19 +189,24 @@ void ChatPacketHandler::HandleFriendRequest(Packet* packet) {
|
||||
Database::Get()->SetBestFriendStatus(requestorPlayerID, requestee.playerID, bestFriendStatus);
|
||||
// Sent the best friend update here if the value is 3
|
||||
if (bestFriendStatus == 3U) {
|
||||
requestee.countOfBestFriends += 1;
|
||||
requestor.countOfBestFriends += 1;
|
||||
if (requestee.sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestee, requestor, eAddFriendResponseType::ACCEPTED, false, true);
|
||||
if (requestor.sysAddr != UNASSIGNED_SYSTEM_ADDRESS) SendFriendResponse(requestor, requestee, eAddFriendResponseType::ACCEPTED, false, true);
|
||||
|
||||
for (auto& friendData : requestor.friends) {
|
||||
if (friendData.friendID == requestee.playerID) {
|
||||
friendData.isBestFriend = true;
|
||||
}
|
||||
}
|
||||
for (auto& friendData : requestee.friends) {
|
||||
if (friendData.friendID == requestor.playerID) {
|
||||
friendData.isBestFriend = true;
|
||||
requestor.countOfBestFriends += 1;
|
||||
|
||||
auto& toModify = Game::playerContainer.GetPlayerDataMutable(playerName);
|
||||
if (toModify) {
|
||||
for (auto& friendData : toModify.friends) {
|
||||
if (friendData.friendID == requestor.playerID) {
|
||||
friendData.isBestFriend = true;
|
||||
}
|
||||
}
|
||||
toModify.countOfBestFriends += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -400,8 +406,8 @@ void ChatPacketHandler::HandleShowAll(Packet* packet) {
|
||||
bitStream.Write(Game::playerContainer.GetSimCount());
|
||||
bitStream.Write<uint8_t>(request.displayIndividualPlayers);
|
||||
bitStream.Write<uint8_t>(request.displayZoneData);
|
||||
if (request.displayZoneData || request.displayIndividualPlayers){
|
||||
for (auto& [playerID, playerData ]: Game::playerContainer.GetAllPlayers()){
|
||||
if (request.displayZoneData || request.displayIndividualPlayers) {
|
||||
for (auto& [playerID, playerData] : Game::playerContainer.GetAllPlayers()) {
|
||||
if (!playerData) continue;
|
||||
bitStream.Write<uint8_t>(0); // structure packing
|
||||
if (request.displayIndividualPlayers) bitStream.Write(LUWString(playerData.playerName));
|
||||
|
||||
@@ -92,10 +92,12 @@ int main(int argc, char** argv) {
|
||||
//Find out the master's IP:
|
||||
std::string masterIP;
|
||||
uint32_t masterPort = 1000;
|
||||
std::string masterPassword;
|
||||
auto masterInfo = Database::Get()->GetMasterInfo();
|
||||
if (masterInfo) {
|
||||
masterIP = masterInfo->ip;
|
||||
masterPort = masterInfo->port;
|
||||
masterPassword = masterInfo->password;
|
||||
}
|
||||
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
|
||||
std::string ourIP = "localhost";
|
||||
@@ -104,7 +106,7 @@ int main(int argc, char** argv) {
|
||||
const auto externalIPString = Game::config->GetValue("external_ip");
|
||||
if (!externalIPString.empty()) ourIP = externalIPString;
|
||||
|
||||
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal);
|
||||
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, &Game::lastSignal, masterPassword);
|
||||
|
||||
const bool dontGenerateDCF = GeneralUtils::TryParse<bool>(Game::config->GetValue("dont_generate_dcf")).value_or(false);
|
||||
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF);
|
||||
@@ -122,6 +124,8 @@ int main(int argc, char** argv) {
|
||||
uint32_t framesSinceMasterDisconnect = 0;
|
||||
uint32_t framesSinceLastSQLPing = 0;
|
||||
|
||||
auto lastTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
Game::logger->Flush(); // once immediately before main loop
|
||||
while (!Game::ShouldShutdown()) {
|
||||
//Check if we're still connected to master:
|
||||
@@ -132,7 +136,11 @@ int main(int argc, char** argv) {
|
||||
break; //Exit our loop, shut down.
|
||||
} else framesSinceMasterDisconnect = 0;
|
||||
|
||||
//In world we'd update our other systems here.
|
||||
const auto currentTime = std::chrono::high_resolution_clock::now();
|
||||
const float deltaTime = std::chrono::duration<float>(currentTime - lastTime).count();
|
||||
lastTime = currentTime;
|
||||
|
||||
Game::playerContainer.Update(deltaTime);
|
||||
|
||||
//Check for packets here:
|
||||
Game::server->ReceiveFromMaster(); //ReceiveFromMaster also handles the master packets if needed.
|
||||
@@ -168,7 +176,7 @@ int main(int argc, char** argv) {
|
||||
t += std::chrono::milliseconds(chatFrameDelta); //Chat can run at a lower "fps"
|
||||
std::this_thread::sleep_until(t);
|
||||
}
|
||||
|
||||
Game::playerContainer.Shutdown();
|
||||
//Delete our objects here:
|
||||
Database::Destroy("ChatServer");
|
||||
delete Game::server;
|
||||
@@ -197,150 +205,150 @@ void HandlePacket(Packet* packet) {
|
||||
inStream.Read(chatMessageID);
|
||||
|
||||
switch (chatMessageID) {
|
||||
case MessageType::Chat::GM_MUTE:
|
||||
Game::playerContainer.MuteUpdate(packet);
|
||||
break;
|
||||
case MessageType::Chat::GM_MUTE:
|
||||
Game::playerContainer.MuteUpdate(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::CREATE_TEAM:
|
||||
Game::playerContainer.CreateTeamServer(packet);
|
||||
break;
|
||||
case MessageType::Chat::CREATE_TEAM:
|
||||
Game::playerContainer.CreateTeamServer(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::GET_FRIENDS_LIST:
|
||||
ChatPacketHandler::HandleFriendlistRequest(packet);
|
||||
break;
|
||||
case MessageType::Chat::GET_FRIENDS_LIST:
|
||||
ChatPacketHandler::HandleFriendlistRequest(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::GET_IGNORE_LIST:
|
||||
ChatIgnoreList::GetIgnoreList(packet);
|
||||
break;
|
||||
case MessageType::Chat::GET_IGNORE_LIST:
|
||||
ChatIgnoreList::GetIgnoreList(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::ADD_IGNORE:
|
||||
ChatIgnoreList::AddIgnore(packet);
|
||||
break;
|
||||
case MessageType::Chat::ADD_IGNORE:
|
||||
ChatIgnoreList::AddIgnore(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::REMOVE_IGNORE:
|
||||
ChatIgnoreList::RemoveIgnore(packet);
|
||||
break;
|
||||
case MessageType::Chat::REMOVE_IGNORE:
|
||||
ChatIgnoreList::RemoveIgnore(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::TEAM_GET_STATUS:
|
||||
ChatPacketHandler::HandleTeamStatusRequest(packet);
|
||||
break;
|
||||
case MessageType::Chat::TEAM_GET_STATUS:
|
||||
ChatPacketHandler::HandleTeamStatusRequest(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::ADD_FRIEND_REQUEST:
|
||||
//this involves someone sending the initial request, the response is below, response as in from the other player.
|
||||
//We basically just check to see if this player is online or not and route the packet.
|
||||
ChatPacketHandler::HandleFriendRequest(packet);
|
||||
break;
|
||||
case MessageType::Chat::ADD_FRIEND_REQUEST:
|
||||
//this involves someone sending the initial request, the response is below, response as in from the other player.
|
||||
//We basically just check to see if this player is online or not and route the packet.
|
||||
ChatPacketHandler::HandleFriendRequest(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::ADD_FRIEND_RESPONSE:
|
||||
//This isn't the response a server sent, rather it is a player's response to a received request.
|
||||
//Here, we'll actually have to add them to eachother's friend lists depending on the response code.
|
||||
ChatPacketHandler::HandleFriendResponse(packet);
|
||||
break;
|
||||
case MessageType::Chat::ADD_FRIEND_RESPONSE:
|
||||
//This isn't the response a server sent, rather it is a player's response to a received request.
|
||||
//Here, we'll actually have to add them to eachother's friend lists depending on the response code.
|
||||
ChatPacketHandler::HandleFriendResponse(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::REMOVE_FRIEND:
|
||||
ChatPacketHandler::HandleRemoveFriend(packet);
|
||||
break;
|
||||
case MessageType::Chat::REMOVE_FRIEND:
|
||||
ChatPacketHandler::HandleRemoveFriend(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::GENERAL_CHAT_MESSAGE:
|
||||
ChatPacketHandler::HandleChatMessage(packet);
|
||||
break;
|
||||
case MessageType::Chat::GENERAL_CHAT_MESSAGE:
|
||||
ChatPacketHandler::HandleChatMessage(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::PRIVATE_CHAT_MESSAGE:
|
||||
//This message is supposed to be echo'd to both the sender and the receiver
|
||||
//BUT: they have to have different responseCodes, so we'll do some of the ol hacky wacky to fix that right up.
|
||||
ChatPacketHandler::HandlePrivateChatMessage(packet);
|
||||
break;
|
||||
case MessageType::Chat::PRIVATE_CHAT_MESSAGE:
|
||||
//This message is supposed to be echo'd to both the sender and the receiver
|
||||
//BUT: they have to have different responseCodes, so we'll do some of the ol hacky wacky to fix that right up.
|
||||
ChatPacketHandler::HandlePrivateChatMessage(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::TEAM_INVITE:
|
||||
ChatPacketHandler::HandleTeamInvite(packet);
|
||||
break;
|
||||
case MessageType::Chat::TEAM_INVITE:
|
||||
ChatPacketHandler::HandleTeamInvite(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::TEAM_INVITE_RESPONSE:
|
||||
ChatPacketHandler::HandleTeamInviteResponse(packet);
|
||||
break;
|
||||
case MessageType::Chat::TEAM_INVITE_RESPONSE:
|
||||
ChatPacketHandler::HandleTeamInviteResponse(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::TEAM_LEAVE:
|
||||
ChatPacketHandler::HandleTeamLeave(packet);
|
||||
break;
|
||||
case MessageType::Chat::TEAM_LEAVE:
|
||||
ChatPacketHandler::HandleTeamLeave(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::TEAM_SET_LEADER:
|
||||
ChatPacketHandler::HandleTeamPromote(packet);
|
||||
break;
|
||||
case MessageType::Chat::TEAM_SET_LEADER:
|
||||
ChatPacketHandler::HandleTeamPromote(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::TEAM_KICK:
|
||||
ChatPacketHandler::HandleTeamKick(packet);
|
||||
break;
|
||||
case MessageType::Chat::TEAM_KICK:
|
||||
ChatPacketHandler::HandleTeamKick(packet);
|
||||
break;
|
||||
|
||||
case MessageType::Chat::TEAM_SET_LOOT:
|
||||
ChatPacketHandler::HandleTeamLootOption(packet);
|
||||
break;
|
||||
case MessageType::Chat::GMLEVEL_UPDATE:
|
||||
ChatPacketHandler::HandleGMLevelUpdate(packet);
|
||||
break;
|
||||
case MessageType::Chat::LOGIN_SESSION_NOTIFY:
|
||||
Game::playerContainer.InsertPlayer(packet);
|
||||
break;
|
||||
case MessageType::Chat::GM_ANNOUNCE:{
|
||||
// we just forward this packet to every connected server
|
||||
inStream.ResetReadPointer();
|
||||
Game::server->Send(inStream, packet->systemAddress, true); // send to everyone except origin
|
||||
}
|
||||
break;
|
||||
case MessageType::Chat::UNEXPECTED_DISCONNECT:
|
||||
Game::playerContainer.RemovePlayer(packet);
|
||||
break;
|
||||
case MessageType::Chat::WHO:
|
||||
ChatPacketHandler::HandleWho(packet);
|
||||
break;
|
||||
case MessageType::Chat::SHOW_ALL:
|
||||
ChatPacketHandler::HandleShowAll(packet);
|
||||
break;
|
||||
case MessageType::Chat::USER_CHANNEL_CHAT_MESSAGE:
|
||||
case MessageType::Chat::WORLD_DISCONNECT_REQUEST:
|
||||
case MessageType::Chat::WORLD_PROXIMITY_RESPONSE:
|
||||
case MessageType::Chat::WORLD_PARCEL_RESPONSE:
|
||||
case MessageType::Chat::TEAM_MISSED_INVITE_CHECK:
|
||||
case MessageType::Chat::GUILD_CREATE:
|
||||
case MessageType::Chat::GUILD_INVITE:
|
||||
case MessageType::Chat::GUILD_INVITE_RESPONSE:
|
||||
case MessageType::Chat::GUILD_LEAVE:
|
||||
case MessageType::Chat::GUILD_KICK:
|
||||
case MessageType::Chat::GUILD_GET_STATUS:
|
||||
case MessageType::Chat::GUILD_GET_ALL:
|
||||
case MessageType::Chat::BLUEPRINT_MODERATED:
|
||||
case MessageType::Chat::BLUEPRINT_MODEL_READY:
|
||||
case MessageType::Chat::PROPERTY_READY_FOR_APPROVAL:
|
||||
case MessageType::Chat::PROPERTY_MODERATION_CHANGED:
|
||||
case MessageType::Chat::PROPERTY_BUILDMODE_CHANGED:
|
||||
case MessageType::Chat::PROPERTY_BUILDMODE_CHANGED_REPORT:
|
||||
case MessageType::Chat::MAIL:
|
||||
case MessageType::Chat::WORLD_INSTANCE_LOCATION_REQUEST:
|
||||
case MessageType::Chat::REPUTATION_UPDATE:
|
||||
case MessageType::Chat::SEND_CANNED_TEXT:
|
||||
case MessageType::Chat::CHARACTER_NAME_CHANGE_REQUEST:
|
||||
case MessageType::Chat::CSR_REQUEST:
|
||||
case MessageType::Chat::CSR_REPLY:
|
||||
case MessageType::Chat::GM_KICK:
|
||||
case MessageType::Chat::WORLD_ROUTE_PACKET:
|
||||
case MessageType::Chat::GET_ZONE_POPULATIONS:
|
||||
case MessageType::Chat::REQUEST_MINIMUM_CHAT_MODE:
|
||||
case MessageType::Chat::MATCH_REQUEST:
|
||||
case MessageType::Chat::UGCMANIFEST_REPORT_MISSING_FILE:
|
||||
case MessageType::Chat::UGCMANIFEST_REPORT_DONE_FILE:
|
||||
case MessageType::Chat::UGCMANIFEST_REPORT_DONE_BLUEPRINT:
|
||||
case MessageType::Chat::UGCC_REQUEST:
|
||||
case MessageType::Chat::WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE:
|
||||
case MessageType::Chat::ACHIEVEMENT_NOTIFY:
|
||||
case MessageType::Chat::GM_CLOSE_PRIVATE_CHAT_WINDOW:
|
||||
case MessageType::Chat::PLAYER_READY:
|
||||
case MessageType::Chat::GET_DONATION_TOTAL:
|
||||
case MessageType::Chat::UPDATE_DONATION:
|
||||
case MessageType::Chat::PRG_CSR_COMMAND:
|
||||
case MessageType::Chat::HEARTBEAT_REQUEST_FROM_WORLD:
|
||||
case MessageType::Chat::UPDATE_FREE_TRIAL_STATUS:
|
||||
LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chatMessageID).data(), chatMessageID);
|
||||
break;
|
||||
default:
|
||||
LOG("Unknown CHAT Message id: %i", chatMessageID);
|
||||
case MessageType::Chat::TEAM_SET_LOOT:
|
||||
ChatPacketHandler::HandleTeamLootOption(packet);
|
||||
break;
|
||||
case MessageType::Chat::GMLEVEL_UPDATE:
|
||||
ChatPacketHandler::HandleGMLevelUpdate(packet);
|
||||
break;
|
||||
case MessageType::Chat::LOGIN_SESSION_NOTIFY:
|
||||
Game::playerContainer.InsertPlayer(packet);
|
||||
break;
|
||||
case MessageType::Chat::GM_ANNOUNCE: {
|
||||
// we just forward this packet to every connected server
|
||||
inStream.ResetReadPointer();
|
||||
Game::server->Send(inStream, packet->systemAddress, true); // send to everyone except origin
|
||||
}
|
||||
break;
|
||||
case MessageType::Chat::UNEXPECTED_DISCONNECT:
|
||||
Game::playerContainer.ScheduleRemovePlayer(packet);
|
||||
break;
|
||||
case MessageType::Chat::WHO:
|
||||
ChatPacketHandler::HandleWho(packet);
|
||||
break;
|
||||
case MessageType::Chat::SHOW_ALL:
|
||||
ChatPacketHandler::HandleShowAll(packet);
|
||||
break;
|
||||
case MessageType::Chat::USER_CHANNEL_CHAT_MESSAGE:
|
||||
case MessageType::Chat::WORLD_DISCONNECT_REQUEST:
|
||||
case MessageType::Chat::WORLD_PROXIMITY_RESPONSE:
|
||||
case MessageType::Chat::WORLD_PARCEL_RESPONSE:
|
||||
case MessageType::Chat::TEAM_MISSED_INVITE_CHECK:
|
||||
case MessageType::Chat::GUILD_CREATE:
|
||||
case MessageType::Chat::GUILD_INVITE:
|
||||
case MessageType::Chat::GUILD_INVITE_RESPONSE:
|
||||
case MessageType::Chat::GUILD_LEAVE:
|
||||
case MessageType::Chat::GUILD_KICK:
|
||||
case MessageType::Chat::GUILD_GET_STATUS:
|
||||
case MessageType::Chat::GUILD_GET_ALL:
|
||||
case MessageType::Chat::BLUEPRINT_MODERATED:
|
||||
case MessageType::Chat::BLUEPRINT_MODEL_READY:
|
||||
case MessageType::Chat::PROPERTY_READY_FOR_APPROVAL:
|
||||
case MessageType::Chat::PROPERTY_MODERATION_CHANGED:
|
||||
case MessageType::Chat::PROPERTY_BUILDMODE_CHANGED:
|
||||
case MessageType::Chat::PROPERTY_BUILDMODE_CHANGED_REPORT:
|
||||
case MessageType::Chat::MAIL:
|
||||
case MessageType::Chat::WORLD_INSTANCE_LOCATION_REQUEST:
|
||||
case MessageType::Chat::REPUTATION_UPDATE:
|
||||
case MessageType::Chat::SEND_CANNED_TEXT:
|
||||
case MessageType::Chat::CHARACTER_NAME_CHANGE_REQUEST:
|
||||
case MessageType::Chat::CSR_REQUEST:
|
||||
case MessageType::Chat::CSR_REPLY:
|
||||
case MessageType::Chat::GM_KICK:
|
||||
case MessageType::Chat::WORLD_ROUTE_PACKET:
|
||||
case MessageType::Chat::GET_ZONE_POPULATIONS:
|
||||
case MessageType::Chat::REQUEST_MINIMUM_CHAT_MODE:
|
||||
case MessageType::Chat::MATCH_REQUEST:
|
||||
case MessageType::Chat::UGCMANIFEST_REPORT_MISSING_FILE:
|
||||
case MessageType::Chat::UGCMANIFEST_REPORT_DONE_FILE:
|
||||
case MessageType::Chat::UGCMANIFEST_REPORT_DONE_BLUEPRINT:
|
||||
case MessageType::Chat::UGCC_REQUEST:
|
||||
case MessageType::Chat::WORLD_PLAYERS_PET_MODERATED_ACKNOWLEDGE:
|
||||
case MessageType::Chat::ACHIEVEMENT_NOTIFY:
|
||||
case MessageType::Chat::GM_CLOSE_PRIVATE_CHAT_WINDOW:
|
||||
case MessageType::Chat::PLAYER_READY:
|
||||
case MessageType::Chat::GET_DONATION_TOTAL:
|
||||
case MessageType::Chat::UPDATE_DONATION:
|
||||
case MessageType::Chat::PRG_CSR_COMMAND:
|
||||
case MessageType::Chat::HEARTBEAT_REQUEST_FROM_WORLD:
|
||||
case MessageType::Chat::UPDATE_FREE_TRIAL_STATUS:
|
||||
LOG("Unhandled CHAT Message id: %s (%i)", StringifiedEnum::ToString(chatMessageID).data(), chatMessageID);
|
||||
break;
|
||||
default:
|
||||
LOG("Unknown CHAT Message id: %i", chatMessageID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,10 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto isLogin = !m_Players.contains(playerId);
|
||||
auto& data = m_Players[playerId];
|
||||
data = PlayerData();
|
||||
data.isLogin = isLogin;
|
||||
data.playerID = playerId;
|
||||
|
||||
uint32_t len;
|
||||
@@ -57,13 +60,32 @@ void PlayerContainer::InsertPlayer(Packet* packet) {
|
||||
LOG("Added user: %s (%llu), zone: %i", data.playerName.c_str(), data.playerID, data.zoneID.GetMapID());
|
||||
|
||||
Database::Get()->UpdateActivityLog(data.playerID, eActivityType::PlayerLoggedIn, data.zoneID.GetMapID());
|
||||
m_PlayersToRemove.erase(playerId);
|
||||
}
|
||||
|
||||
void PlayerContainer::RemovePlayer(Packet* packet) {
|
||||
void PlayerContainer::ScheduleRemovePlayer(Packet* packet) {
|
||||
CINSTREAM_SKIP_HEADER;
|
||||
LWOOBJID playerID;
|
||||
LWOOBJID playerID{ LWOOBJID_EMPTY };
|
||||
inStream.Read(playerID);
|
||||
constexpr float updatePlayerOnLogoutTime = 20.0f;
|
||||
if (playerID != LWOOBJID_EMPTY) m_PlayersToRemove.insert_or_assign(playerID, updatePlayerOnLogoutTime);
|
||||
}
|
||||
|
||||
void PlayerContainer::Update(const float deltaTime) {
|
||||
for (auto it = m_PlayersToRemove.begin(); it != m_PlayersToRemove.end();) {
|
||||
auto& [id, time] = *it;
|
||||
time -= deltaTime;
|
||||
|
||||
if (time <= 0.0f) {
|
||||
RemovePlayer(id);
|
||||
it = m_PlayersToRemove.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PlayerContainer::RemovePlayer(const LWOOBJID playerID) {
|
||||
//Before they get kicked, we need to also send a message to their friends saying that they disconnected.
|
||||
const auto& player = GetPlayerData(playerID);
|
||||
|
||||
@@ -417,3 +439,13 @@ const PlayerData& PlayerContainer::GetPlayerData(const LWOOBJID& playerID) {
|
||||
const PlayerData& PlayerContainer::GetPlayerData(const std::string& playerName) {
|
||||
return GetPlayerDataMutable(playerName);
|
||||
}
|
||||
|
||||
void PlayerContainer::Shutdown() {
|
||||
m_Players.erase(LWOOBJID_EMPTY);
|
||||
while (!m_Players.empty()) {
|
||||
const auto& [id, playerData] = *m_Players.begin();
|
||||
Database::Get()->UpdateActivityLog(id, eActivityType::PlayerLoggedOut, playerData.zoneID.GetMapID());
|
||||
m_Players.erase(m_Players.begin());
|
||||
}
|
||||
for (auto* team : mTeams) if (team) delete team;
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ struct PlayerData {
|
||||
std::vector<IgnoreData> ignoredPlayers;
|
||||
eGameMasterLevel gmLevel = static_cast<eGameMasterLevel>(0); // CIVILLIAN
|
||||
bool isFTP = false;
|
||||
bool isLogin = false;
|
||||
};
|
||||
|
||||
struct TeamData {
|
||||
@@ -62,10 +63,12 @@ class PlayerContainer {
|
||||
public:
|
||||
void Initialize();
|
||||
void InsertPlayer(Packet* packet);
|
||||
void RemovePlayer(Packet* packet);
|
||||
void ScheduleRemovePlayer(Packet* packet);
|
||||
void RemovePlayer(const LWOOBJID playerID);
|
||||
void MuteUpdate(Packet* packet);
|
||||
void CreateTeamServer(Packet* packet);
|
||||
void BroadcastMuteUpdate(LWOOBJID player, time_t time);
|
||||
void Shutdown();
|
||||
|
||||
const PlayerData& GetPlayerData(const LWOOBJID& playerID);
|
||||
const PlayerData& GetPlayerData(const std::string& playerName);
|
||||
@@ -89,11 +92,15 @@ public:
|
||||
uint32_t GetMaxNumberOfBestFriends() { return m_MaxNumberOfBestFriends; }
|
||||
uint32_t GetMaxNumberOfFriends() { return m_MaxNumberOfFriends; }
|
||||
|
||||
void Update(const float deltaTime);
|
||||
bool PlayerBeingRemoved(const LWOOBJID playerID) { return m_PlayersToRemove.contains(playerID); }
|
||||
|
||||
private:
|
||||
LWOOBJID m_TeamIDCounter = 0;
|
||||
std::map<LWOOBJID, PlayerData> m_Players;
|
||||
std::vector<TeamData*> mTeams;
|
||||
std::unordered_map<LWOOBJID, std::u16string> m_Names;
|
||||
std::map<LWOOBJID, float> m_PlayersToRemove;
|
||||
uint32_t m_MaxNumberOfBestFriends = 5;
|
||||
uint32_t m_MaxNumberOfFriends = 50;
|
||||
uint32_t m_PlayerCount = 0;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Logger.h"
|
||||
#include "Game.h"
|
||||
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@@ -257,10 +258,10 @@ public:
|
||||
*
|
||||
* @param key The key to remove from the associative portion
|
||||
*/
|
||||
void Remove(const std::string& key, const bool deleteValue = true) {
|
||||
void Remove(const std::string& key) {
|
||||
const AMFAssociative::const_iterator it = m_Associative.find(key);
|
||||
if (it != m_Associative.cend()) {
|
||||
if (deleteValue) m_Associative.erase(it);
|
||||
m_Associative.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,6 +344,11 @@ public:
|
||||
return index < m_Dense.size() ? m_Dense.at(index).get() : nullptr;
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
m_Associative.clear();
|
||||
m_Dense.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* The associative portion. These values are key'd with strings to an AMFValue.
|
||||
|
||||
@@ -957,6 +957,7 @@ namespace MessageType {
|
||||
MODIFY_PLAYER_ZONE_STATISTIC = 1046,
|
||||
APPLY_EXTERNAL_FORCE = 1049,
|
||||
GET_APPLIED_EXTERNAL_FORCE = 1050,
|
||||
ACTIVITY_NOTIFY = 1051,
|
||||
ITEM_EQUIPPED = 1052,
|
||||
ACTIVITY_STATE_CHANGE_REQUEST = 1053,
|
||||
OVERRIDE_FRICTION = 1054,
|
||||
|
||||
@@ -14,7 +14,7 @@ public:
|
||||
uint32_t lastPlayedTimestamp{};
|
||||
float primaryScore{};
|
||||
float secondaryScore{};
|
||||
uint32_t tertiaryScore{};
|
||||
float tertiaryScore{};
|
||||
uint32_t numWins{};
|
||||
uint32_t numTimesPlayed{};
|
||||
uint32_t ranking{};
|
||||
|
||||
@@ -9,10 +9,11 @@ public:
|
||||
struct MasterInfo {
|
||||
std::string ip;
|
||||
uint32_t port{};
|
||||
std::string password{};
|
||||
};
|
||||
|
||||
// Set the master server ip and port.
|
||||
virtual void SetMasterIp(const std::string_view ip, const uint32_t port) = 0;
|
||||
virtual void SetMasterInfo(const MasterInfo& info) = 0;
|
||||
|
||||
// Get the master server info.
|
||||
virtual std::optional<MasterInfo> GetMasterInfo() = 0;
|
||||
|
||||
@@ -96,7 +96,7 @@ public:
|
||||
void UpdateAccountBan(const uint32_t accountId, const bool banned) override;
|
||||
void UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) override;
|
||||
void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) override;
|
||||
void SetMasterIp(const std::string_view ip, const uint32_t port) override;
|
||||
void SetMasterInfo(const IServers::MasterInfo& info) override;
|
||||
std::optional<uint32_t> GetCurrentPersistentId() override;
|
||||
void InsertDefaultPersistentId() override;
|
||||
void UpdatePersistentId(const uint32_t id) override;
|
||||
|
||||
@@ -56,6 +56,7 @@ std::optional<IProperty::PropertyEntranceResult> MySQLDatabase::GetProperties(co
|
||||
params.playerId
|
||||
);
|
||||
if (count->next()) {
|
||||
if (!result) result = IProperty::PropertyEntranceResult();
|
||||
result->totalEntriesMatchingQuery = count->getUInt("count");
|
||||
}
|
||||
} else {
|
||||
@@ -109,11 +110,13 @@ std::optional<IProperty::PropertyEntranceResult> MySQLDatabase::GetProperties(co
|
||||
params.playerSort
|
||||
);
|
||||
if (count->next()) {
|
||||
if (!result) result = IProperty::PropertyEntranceResult();
|
||||
result->totalEntriesMatchingQuery = count->getUInt("count");
|
||||
}
|
||||
}
|
||||
|
||||
while (properties->next()) {
|
||||
if (!result) result = IProperty::PropertyEntranceResult();
|
||||
auto& entry = result->entries.emplace_back();
|
||||
entry.id = properties->getUInt64("id");
|
||||
entry.ownerId = properties->getUInt64("owner_id");
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "MySQLDatabase.h"
|
||||
|
||||
void MySQLDatabase::SetMasterIp(const std::string_view ip, const uint32_t port) {
|
||||
void MySQLDatabase::SetMasterInfo(const MasterInfo& info) {
|
||||
// We only want our 1 entry anyways, so we can just delete all and reinsert the one we want
|
||||
// since it would be two queries anyways.
|
||||
ExecuteDelete("TRUNCATE TABLE servers;");
|
||||
ExecuteInsert("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`) VALUES ('master', ?, ?, 0, 171022)", ip, port);
|
||||
ExecuteInsert("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`, `master_password`) VALUES ('master', ?, ?, 0, 171022, ?)", info.ip, info.port, info.password);
|
||||
}
|
||||
|
||||
std::optional<IServers::MasterInfo> MySQLDatabase::GetMasterInfo() {
|
||||
auto result = ExecuteSelect("SELECT ip, port FROM servers WHERE name='master' LIMIT 1;");
|
||||
auto result = ExecuteSelect("SELECT ip, port, master_password FROM servers WHERE name='master' LIMIT 1;");
|
||||
|
||||
if (!result->next()) {
|
||||
return std::nullopt;
|
||||
@@ -18,6 +18,7 @@ std::optional<IServers::MasterInfo> MySQLDatabase::GetMasterInfo() {
|
||||
|
||||
toReturn.ip = result->getString("ip").c_str();
|
||||
toReturn.port = result->getInt("port");
|
||||
toReturn.password = result->getString("master_password").c_str();
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public:
|
||||
void UpdateAccountBan(const uint32_t accountId, const bool banned) override;
|
||||
void UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) override;
|
||||
void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) override;
|
||||
void SetMasterIp(const std::string_view ip, const uint32_t port) override;
|
||||
void SetMasterInfo(const IServers::MasterInfo& info) override;
|
||||
std::optional<uint32_t> GetCurrentPersistentId() override;
|
||||
void InsertDefaultPersistentId() override;
|
||||
void UpdatePersistentId(const uint32_t id) override;
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
#include "SQLiteDatabase.h"
|
||||
|
||||
void SQLiteDatabase::SetMasterIp(const std::string_view ip, const uint32_t port) {
|
||||
void SQLiteDatabase::SetMasterInfo(const MasterInfo& info) {
|
||||
// We only want our 1 entry anyways, so we can just delete all and reinsert the one we want
|
||||
// since it would be two queries anyways.
|
||||
ExecuteDelete("DELETE FROM servers;");
|
||||
ExecuteInsert("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`) VALUES ('master', ?, ?, 0, 171022)", ip, port);
|
||||
ExecuteInsert("INSERT INTO `servers` (`name`, `ip`, `port`, `state`, `version`, `master_password`) VALUES ('master', ?, ?, 0, 171022 ?)", info.ip, info.port, info.password);
|
||||
}
|
||||
|
||||
std::optional<IServers::MasterInfo> SQLiteDatabase::GetMasterInfo() {
|
||||
auto [_, result] = ExecuteSelect("SELECT ip, port FROM servers WHERE name='master' LIMIT 1;");
|
||||
auto [_, result] = ExecuteSelect("SELECT ip, port, master_password FROM servers WHERE name='master' LIMIT 1;");
|
||||
|
||||
if (result.eof()) {
|
||||
return std::nullopt;
|
||||
@@ -18,6 +18,7 @@ std::optional<IServers::MasterInfo> SQLiteDatabase::GetMasterInfo() {
|
||||
|
||||
toReturn.ip = result.getStringField("ip");
|
||||
toReturn.port = result.getIntField("port");
|
||||
toReturn.password = result.getStringField("master_password");
|
||||
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ void TestSQLDatabase::InsertNewAccount(const std::string_view username, const st
|
||||
|
||||
}
|
||||
|
||||
void TestSQLDatabase::SetMasterIp(const std::string_view ip, const uint32_t port) {
|
||||
void TestSQLDatabase::SetMasterInfo(const IServers::MasterInfo& info) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ class TestSQLDatabase : public GameDatabase {
|
||||
void UpdateAccountBan(const uint32_t accountId, const bool banned) override;
|
||||
void UpdateAccountPassword(const uint32_t accountId, const std::string_view bcryptpassword) override;
|
||||
void InsertNewAccount(const std::string_view username, const std::string_view bcryptpassword) override;
|
||||
void SetMasterIp(const std::string_view ip, const uint32_t port) override;
|
||||
void SetMasterInfo(const IServers::MasterInfo& info) override;
|
||||
std::optional<uint32_t> GetCurrentPersistentId() override;
|
||||
void InsertDefaultPersistentId() override;
|
||||
void UpdatePersistentId(const uint32_t id) override;
|
||||
|
||||
@@ -296,6 +296,12 @@ void Character::SaveXMLToDatabase() {
|
||||
flags->LinkEndChild(s);
|
||||
}
|
||||
|
||||
if (GetPlayerFlag(ePlayerFlag::EQUPPED_TRIAL_FACTION_GEAR)) {
|
||||
auto* s = m_Doc.NewElement("s");
|
||||
s->SetAttribute("si", ePlayerFlag::EQUPPED_TRIAL_FACTION_GEAR);
|
||||
flags->LinkEndChild(s);
|
||||
}
|
||||
|
||||
SaveXmlRespawnCheckpoints();
|
||||
|
||||
//Call upon the entity to update our xmlDoc:
|
||||
@@ -357,49 +363,62 @@ void Character::SetPlayerFlag(const uint32_t flagId, const bool value) {
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the index first
|
||||
auto flagIndex = uint32_t(std::floor(flagId / 64));
|
||||
|
||||
const auto shiftedValue = 1ULL << flagId % 64;
|
||||
|
||||
auto it = m_PlayerFlags.find(flagIndex);
|
||||
|
||||
// Check if flag index exists
|
||||
if (it != m_PlayerFlags.end()) {
|
||||
// Update the value
|
||||
if (value) {
|
||||
it->second |= shiftedValue;
|
||||
} else {
|
||||
it->second &= ~shiftedValue;
|
||||
}
|
||||
if (flagId == EQUPPED_TRIAL_FACTION_GEAR || flagId == IS_NEWS_SCREEN_VISIBLE) {
|
||||
if (value) m_SessionFlags.insert(flagId);
|
||||
else m_SessionFlags.erase(flagId);
|
||||
} else {
|
||||
if (value) {
|
||||
// Otherwise, insert the value
|
||||
uint64_t flagValue = 0;
|
||||
// Calculate the index first
|
||||
auto flagIndex = uint32_t(std::floor(flagId / 64));
|
||||
|
||||
flagValue |= shiftedValue;
|
||||
const auto shiftedValue = 1ULL << flagId % 64;
|
||||
|
||||
m_PlayerFlags.insert(std::make_pair(flagIndex, flagValue));
|
||||
auto it = m_PlayerFlags.find(flagIndex);
|
||||
|
||||
// Check if flag index exists
|
||||
if (it != m_PlayerFlags.end()) {
|
||||
// Update the value
|
||||
if (value) {
|
||||
it->second |= shiftedValue;
|
||||
} else {
|
||||
it->second &= ~shiftedValue;
|
||||
}
|
||||
} else {
|
||||
if (value) {
|
||||
// Otherwise, insert the value
|
||||
uint64_t flagValue = 0;
|
||||
|
||||
flagValue |= shiftedValue;
|
||||
|
||||
m_PlayerFlags.insert(std::make_pair(flagIndex, flagValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify the client that a flag has changed server-side
|
||||
GameMessages::SendNotifyClientFlagChange(m_ObjectID, flagId, value, m_ParentUser->GetSystemAddress());
|
||||
}
|
||||
|
||||
bool Character::GetPlayerFlag(const uint32_t flagId) const {
|
||||
// Calculate the index first
|
||||
const auto flagIndex = uint32_t(std::floor(flagId / 64));
|
||||
using enum ePlayerFlag;
|
||||
|
||||
const auto shiftedValue = 1ULL << flagId % 64;
|
||||
bool toReturn = false; //by def, return false.
|
||||
|
||||
auto it = m_PlayerFlags.find(flagIndex);
|
||||
if (it != m_PlayerFlags.end()) {
|
||||
// Don't set the data if we don't have to
|
||||
return (it->second & shiftedValue) != 0;
|
||||
// TODO make actual session flag checker using flags table in database.
|
||||
if (flagId == EQUPPED_TRIAL_FACTION_GEAR || flagId == IS_NEWS_SCREEN_VISIBLE) {
|
||||
toReturn = m_SessionFlags.contains(flagId);
|
||||
} else {
|
||||
// Calculate the index first
|
||||
const auto flagIndex = uint32_t(std::floor(flagId / 64));
|
||||
|
||||
const auto shiftedValue = 1ULL << flagId % 64;
|
||||
|
||||
auto it = m_PlayerFlags.find(flagIndex);
|
||||
if (it != m_PlayerFlags.end()) {
|
||||
// Don't set the data if we don't have to
|
||||
toReturn = (it->second & shiftedValue) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false; //by def, return false.
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
void Character::SetRetroactiveFlags() {
|
||||
|
||||
@@ -620,6 +620,12 @@ private:
|
||||
*/
|
||||
uint64_t m_LastLogin{};
|
||||
|
||||
/**
|
||||
* Flags only set for the duration of a session
|
||||
*
|
||||
*/
|
||||
std::set<uint32_t> m_SessionFlags;
|
||||
|
||||
/**
|
||||
* The gameplay flags this character has (not just true values)
|
||||
*/
|
||||
|
||||
@@ -386,6 +386,9 @@ void Entity::Initialize() {
|
||||
if (m_Character) {
|
||||
comp->LoadFromXml(m_Character->GetXMLDoc());
|
||||
} else {
|
||||
// extraInfo overrides. Client ORs the database smashable and the luz smashable.
|
||||
comp->SetIsSmashable(comp->GetIsSmashable() | isSmashable);
|
||||
|
||||
if (componentID > 0) {
|
||||
std::vector<CDDestructibleComponent> destCompData = destCompTable->Query([=](CDDestructibleComponent entry) { return (entry.id == componentID); });
|
||||
|
||||
@@ -420,9 +423,6 @@ void Entity::Initialize() {
|
||||
comp->SetMinCoins(currencyValues[0].minvalue);
|
||||
comp->SetMaxCoins(currencyValues[0].maxvalue);
|
||||
}
|
||||
|
||||
// extraInfo overrides. Client ORs the database smashable and the luz smashable.
|
||||
comp->SetIsSmashable(comp->GetIsSmashable() | isSmashable);
|
||||
}
|
||||
} else {
|
||||
comp->SetHealth(1);
|
||||
@@ -775,6 +775,12 @@ void Entity::Initialize() {
|
||||
// Hacky way to trigger these when the object has had a chance to get constructed
|
||||
AddCallbackTimer(0, [this]() {
|
||||
this->GetScript()->OnStartup(this);
|
||||
if (this->m_ParentEntity) {
|
||||
GameMessages::ChildLoaded childLoaded;
|
||||
childLoaded.childID = this->m_ObjectID;
|
||||
childLoaded.templateID = this->GetLOT();
|
||||
this->m_ParentEntity->OnChildLoaded(childLoaded);
|
||||
}
|
||||
});
|
||||
|
||||
if (!m_Character && Game::entityManager->GetGhostingEnabled()) {
|
||||
@@ -854,6 +860,9 @@ void Entity::Subscribe(LWOOBJID scriptObjId, CppScripts::Script* scriptToAdd, co
|
||||
auto* destroyableComponent = GetComponent<DestroyableComponent>();
|
||||
if (!destroyableComponent) return;
|
||||
destroyableComponent->Subscribe(scriptObjId, scriptToAdd);
|
||||
} else if (notificationName == "PlayerResurrectionFinished") {
|
||||
LOG("Subscribing to PlayerResurrectionFinished");
|
||||
m_Subscriptions[scriptObjId][notificationName] = scriptToAdd;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -862,6 +871,9 @@ void Entity::Unsubscribe(LWOOBJID scriptObjId, const std::string& notificationNa
|
||||
auto* destroyableComponent = GetComponent<DestroyableComponent>();
|
||||
if (!destroyableComponent) return;
|
||||
destroyableComponent->Unsubscribe(scriptObjId);
|
||||
} else if (notificationName == "PlayerResurrectionFinished") {
|
||||
LOG("Unsubscribing from PlayerResurrectionFinished");
|
||||
m_Subscriptions[scriptObjId].erase(notificationName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1493,6 +1505,27 @@ void Entity::OnChoiceBoxResponse(Entity* sender, int32_t button, const std::u16s
|
||||
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::OnChildLoaded(GameMessages::ChildLoaded& childLoaded) {
|
||||
GetScript()->OnChildLoaded(*this, childLoaded);
|
||||
}
|
||||
|
||||
void Entity::NotifyPlayerResurrectionFinished(GameMessages::PlayerResurrectionFinished& msg) {
|
||||
for (const auto& [id, scriptList] : m_Subscriptions) {
|
||||
auto it = scriptList.find("PlayerResurrectionFinished");
|
||||
if (it == scriptList.end()) continue;
|
||||
|
||||
it->second->NotifyPlayerResurrectionFinished(*this, msg);
|
||||
}
|
||||
}
|
||||
|
||||
void Entity::RequestActivityExit(Entity* sender, LWOOBJID player, bool canceled) {
|
||||
GetScript()->OnRequestActivityExit(sender, player, canceled);
|
||||
}
|
||||
@@ -1532,7 +1565,7 @@ void Entity::Kill(Entity* murderer, const eKillType killType) {
|
||||
|
||||
m_DieCallbacks.clear();
|
||||
|
||||
//OMAI WA MOU, SHINDERIU
|
||||
//お前はもう死んでいる
|
||||
|
||||
GetScript()->OnDie(this, murderer);
|
||||
|
||||
@@ -2175,7 +2208,7 @@ void Entity::SetRespawnRot(const NiQuaternion& rotation) {
|
||||
|
||||
int32_t Entity::GetCollisionGroup() const {
|
||||
for (const auto* component : m_Components | std::views::values) {
|
||||
auto* compToCheck = dynamic_cast<const PhysicsComponent*>(component);
|
||||
auto* compToCheck = dynamic_cast<const PhysicsComponent*>(component);
|
||||
if (compToCheck) {
|
||||
return compToCheck->GetCollisionGroup();
|
||||
}
|
||||
|
||||
@@ -13,6 +13,13 @@
|
||||
#include "eKillType.h"
|
||||
#include "Observable.h"
|
||||
|
||||
namespace GameMessages {
|
||||
struct ActivityNotify;
|
||||
struct ShootingGalleryFire;
|
||||
struct ChildLoaded;
|
||||
struct PlayerResurrectionFinished;
|
||||
};
|
||||
|
||||
namespace Loot {
|
||||
class Info;
|
||||
};
|
||||
@@ -210,6 +217,10 @@ public:
|
||||
void OnZonePropertyModelRemoved(Entity* player);
|
||||
void OnZonePropertyModelRemovedWhileEquipped(Entity* player);
|
||||
void OnZonePropertyModelRotated(Entity* player);
|
||||
void OnActivityNotify(GameMessages::ActivityNotify& notify);
|
||||
void OnShootingGalleryFire(GameMessages::ShootingGalleryFire& notify);
|
||||
void OnChildLoaded(GameMessages::ChildLoaded& childLoaded);
|
||||
void NotifyPlayerResurrectionFinished(GameMessages::PlayerResurrectionFinished& msg);
|
||||
|
||||
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);
|
||||
@@ -363,6 +374,9 @@ protected:
|
||||
* Collision
|
||||
*/
|
||||
std::vector<LWOOBJID> m_TargetsInPhantom;
|
||||
|
||||
// objectID of receiver and map of notification name to script
|
||||
std::map<LWOOBJID, std::map<std::string, CppScripts::Script*>> m_Subscriptions;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -95,7 +95,7 @@ void QueryToLdf(Leaderboard& leaderboard, const std::vector<ILeaderboard::Entry>
|
||||
// Score:1
|
||||
entry.push_back(new LDFData<int32_t>(u"Streak", leaderboardEntry.secondaryScore));
|
||||
// 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
|
||||
break;
|
||||
case Racing:
|
||||
@@ -199,9 +199,9 @@ std::vector<ILeaderboard::Entry> FilterFriends(const std::vector<ILeaderboard::E
|
||||
std::vector<ILeaderboard::Entry> friendsLeaderboard;
|
||||
for (const auto& entry : leaderboard) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,9 +69,10 @@ InventoryComponent::InventoryComponent(Entity* parent) : Component(parent) {
|
||||
auto slot = 0u;
|
||||
|
||||
for (const auto& item : items) {
|
||||
if (!item.equip || !Inventory::IsValidItem(item.itemid)) {
|
||||
continue;
|
||||
}
|
||||
if (!Inventory::IsValidItem(item.itemid)) continue;
|
||||
AddItem(item.itemid, item.count);
|
||||
|
||||
if (!item.equip) continue;
|
||||
|
||||
const LWOOBJID id = ObjectIDManager::GenerateObjectID();
|
||||
|
||||
|
||||
@@ -265,6 +265,7 @@ void MovementAIComponent::PullToPoint(const NiPoint3& point) {
|
||||
|
||||
void MovementAIComponent::SetPath(std::vector<PathWaypoint> path) {
|
||||
if (path.empty()) return;
|
||||
while (!m_CurrentPath.empty()) m_CurrentPath.pop();
|
||||
std::for_each(path.rbegin(), path.rend() - 1, [this](const PathWaypoint& point) {
|
||||
this->m_CurrentPath.push(point);
|
||||
});
|
||||
|
||||
@@ -524,7 +524,7 @@ void PetComponent::NotifyTamingBuildSuccess(NiPoint3 position) {
|
||||
|
||||
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);
|
||||
|
||||
if (item == nullptr) {
|
||||
|
||||
@@ -84,7 +84,12 @@ dpEntity* PhysicsComponent::CreatePhysicsEntity(eReplicaComponentType type) {
|
||||
} else if (info->physicsAsset == "env\\env_won_fv_gas-blocking-volume.hkx") {
|
||||
toReturn = new dpEntity(m_Parent->GetObjectID(), 390.496826f, 111.467964f, 600.821534f, true);
|
||||
m_Position.y -= (111.467964f * m_Parent->GetDefaultScale()) / 2;
|
||||
} else {
|
||||
// Leaving these out for now since they cause more issues than they solve in racing tracks without proper OBB checks.
|
||||
} /* else if (info->physicsAsset == "env\\GFTrack_DeathVolume1_CaveExit.hkx") {
|
||||
toReturn = new dpEntity(m_Parent->GetObjectID(), 112.416870f, 50.363434f, 87.679268f);
|
||||
} else if (info->physicsAsset == "env\\GFTrack_DeathVolume2_RoadGaps.hkx") {
|
||||
toReturn = new dpEntity(m_Parent->GetObjectID(), 48.386536f, 50.363434f, 259.361755f);
|
||||
} */ else {
|
||||
// LOG_DEBUG("This one is supposed to have %s", info->physicsAsset.c_str());
|
||||
|
||||
//add fallback cube:
|
||||
|
||||
@@ -65,14 +65,7 @@ void QuickBuildComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsIni
|
||||
|
||||
outBitStream.Write(false);
|
||||
}
|
||||
// If build state is completed and we've already serialized once in the completed state,
|
||||
// don't serializing this component anymore as this will cause the build to jump again.
|
||||
// If state changes, serialization will begin again.
|
||||
if (!m_StateDirty && m_State == eQuickBuildState::COMPLETED) {
|
||||
outBitStream.Write0();
|
||||
outBitStream.Write0();
|
||||
return;
|
||||
}
|
||||
|
||||
// BEGIN Scripted Activity
|
||||
outBitStream.Write1();
|
||||
|
||||
@@ -90,36 +83,27 @@ void QuickBuildComponent::Serialize(RakNet::BitStream& outBitStream, bool bIsIni
|
||||
}
|
||||
// END Scripted Activity
|
||||
|
||||
outBitStream.Write1();
|
||||
outBitStream.Write(m_StateDirty || bIsInitialUpdate);
|
||||
if (m_StateDirty || bIsInitialUpdate) {
|
||||
outBitStream.Write(m_State);
|
||||
|
||||
outBitStream.Write(m_State);
|
||||
outBitStream.Write(m_ShowResetEffect);
|
||||
outBitStream.Write(m_Activator != nullptr);
|
||||
|
||||
outBitStream.Write(m_ShowResetEffect);
|
||||
outBitStream.Write(m_Activator != nullptr);
|
||||
outBitStream.Write(m_Timer);
|
||||
outBitStream.Write(m_TimerIncomplete);
|
||||
|
||||
outBitStream.Write(m_Timer);
|
||||
outBitStream.Write(m_TimerIncomplete);
|
||||
|
||||
if (bIsInitialUpdate) {
|
||||
outBitStream.Write(false);
|
||||
outBitStream.Write(m_ActivatorPosition);
|
||||
outBitStream.Write(m_RepositionPlayer);
|
||||
if (bIsInitialUpdate) {
|
||||
outBitStream.Write(false); // IsChoiceBuild
|
||||
outBitStream.Write(m_ActivatorPosition);
|
||||
outBitStream.Write(m_RepositionPlayer);
|
||||
}
|
||||
m_StateDirty = false;
|
||||
}
|
||||
m_StateDirty = false;
|
||||
}
|
||||
|
||||
void QuickBuildComponent::Update(float deltaTime) {
|
||||
m_Activator = GetActivator();
|
||||
|
||||
// Serialize the quickbuild every so often, fixes the odd bug where the quickbuild is not buildable
|
||||
/*if (m_SoftTimer > 0.0f) {
|
||||
m_SoftTimer -= deltaTime;
|
||||
}
|
||||
else {
|
||||
m_SoftTimer = 5.0f;
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}*/
|
||||
SetActivator(GetActivator());
|
||||
|
||||
switch (m_State) {
|
||||
case eQuickBuildState::OPEN: {
|
||||
@@ -130,12 +114,12 @@ void QuickBuildComponent::Update(float deltaTime) {
|
||||
const bool isSmashGroup = spawner != nullptr ? spawner->GetIsSpawnSmashGroup() : false;
|
||||
|
||||
if (isSmashGroup) {
|
||||
m_TimerIncomplete += deltaTime;
|
||||
ModifyIncompleteTimer(deltaTime);
|
||||
|
||||
// For reset times < 0 this has to be handled manually
|
||||
if (m_TimeBeforeSmash > 0) {
|
||||
if (m_TimerIncomplete >= m_TimeBeforeSmash - 4.0f) {
|
||||
m_ShowResetEffect = true;
|
||||
if (m_TimerIncomplete >= m_TimeBeforeSmash - 4.0f && !m_ShowResetEffect) {
|
||||
SetShowResetEffect(true);
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
@@ -153,21 +137,19 @@ void QuickBuildComponent::Update(float deltaTime) {
|
||||
break;
|
||||
}
|
||||
case eQuickBuildState::COMPLETED: {
|
||||
m_Timer += deltaTime;
|
||||
ModifyTimer(deltaTime);
|
||||
|
||||
// For reset times < 0 this has to be handled manually
|
||||
if (m_ResetTime > 0) {
|
||||
if (m_Timer >= m_ResetTime - 4.0f) {
|
||||
if (!m_ShowResetEffect) {
|
||||
m_ShowResetEffect = true;
|
||||
if (m_Timer >= m_ResetTime - 4.0f && !m_ShowResetEffect) {
|
||||
SetShowResetEffect(true);
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
|
||||
if (m_Timer >= m_ResetTime) {
|
||||
|
||||
GameMessages::SendDieNoImplCode(m_Parent, LWOOBJID_EMPTY, LWOOBJID_EMPTY, eKillType::VIOLENT, u"", 0.0f, 0.0f, 0.0f, false, true);
|
||||
GameMessages::SendDieNoImplCode(m_Parent, LWOOBJID_EMPTY, LWOOBJID_EMPTY, eKillType::VIOLENT, u"", 0.0f, 0.0f, 7.0f, false, true);
|
||||
|
||||
ResetQuickBuild(false);
|
||||
}
|
||||
@@ -185,9 +167,9 @@ void QuickBuildComponent::Update(float deltaTime) {
|
||||
}
|
||||
|
||||
m_TimeBeforeDrain -= deltaTime;
|
||||
m_Timer += deltaTime;
|
||||
m_TimerIncomplete = 0;
|
||||
m_ShowResetEffect = false;
|
||||
ModifyTimer(deltaTime);
|
||||
SetIncompleteTimer(0.0f);
|
||||
SetShowResetEffect(false);
|
||||
|
||||
if (m_TimeBeforeDrain <= 0.0f) {
|
||||
m_TimeBeforeDrain = m_CompleteTime / static_cast<float>(m_TakeImagination);
|
||||
@@ -215,12 +197,12 @@ void QuickBuildComponent::Update(float deltaTime) {
|
||||
break;
|
||||
}
|
||||
case eQuickBuildState::INCOMPLETE: {
|
||||
m_TimerIncomplete += deltaTime;
|
||||
ModifyIncompleteTimer(deltaTime);
|
||||
|
||||
// For reset times < 0 this has to be handled manually
|
||||
if (m_TimeBeforeSmash > 0) {
|
||||
if (m_TimerIncomplete >= m_TimeBeforeSmash - 4.0f) {
|
||||
m_ShowResetEffect = true;
|
||||
if (m_TimerIncomplete >= m_TimeBeforeSmash - 4.0f && !m_ShowResetEffect) {
|
||||
SetShowResetEffect(true);
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
@@ -260,7 +242,7 @@ void QuickBuildComponent::SpawnActivator() {
|
||||
info.spawnerID = m_Parent->GetObjectID();
|
||||
info.pos = m_ActivatorPosition == NiPoint3Constant::ZERO ? m_Parent->GetPosition() : m_ActivatorPosition;
|
||||
|
||||
m_Activator = Game::entityManager->CreateEntity(info, nullptr, m_Parent);
|
||||
SetActivator(Game::entityManager->CreateEntity(info, nullptr, m_Parent));
|
||||
if (m_Activator) {
|
||||
m_ActivatorId = m_Activator->GetObjectID();
|
||||
Game::entityManager->ConstructEntity(m_Activator);
|
||||
@@ -277,7 +259,7 @@ void QuickBuildComponent::DespawnActivator() {
|
||||
|
||||
m_Activator->ScheduleKillAfterUpdate();
|
||||
|
||||
m_Activator = nullptr;
|
||||
SetActivator(nullptr);
|
||||
|
||||
m_ActivatorId = LWOOBJID_EMPTY;
|
||||
}
|
||||
@@ -405,8 +387,7 @@ void QuickBuildComponent::StartQuickBuild(Entity* const user) {
|
||||
GameMessages::SendQuickBuildNotifyState(m_Parent, m_State, eQuickBuildState::BUILDING, user->GetObjectID());
|
||||
GameMessages::SendEnableQuickBuild(m_Parent, true, false, false, eQuickBuildFailReason::NOT_GIVEN, 0.0f, user->GetObjectID());
|
||||
|
||||
m_State = eQuickBuildState::BUILDING;
|
||||
m_StateDirty = true;
|
||||
SetState(eQuickBuildState::BUILDING);
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
|
||||
auto* movingPlatform = m_Parent->GetComponent<MovingPlatformComponent>();
|
||||
@@ -444,9 +425,8 @@ void QuickBuildComponent::CompleteQuickBuild(Entity* const user) {
|
||||
GameMessages::SendTerminateInteraction(user->GetObjectID(), eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID());
|
||||
|
||||
|
||||
m_State = eQuickBuildState::COMPLETED;
|
||||
m_StateDirty = true;
|
||||
m_Timer = 0.0f;
|
||||
SetState(eQuickBuildState::COMPLETED);
|
||||
SetTimer(0.0f);
|
||||
m_DrainedImagination = 0;
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
@@ -526,11 +506,10 @@ void QuickBuildComponent::ResetQuickBuild(const bool failed) {
|
||||
|
||||
GameMessages::SendQuickBuildNotifyState(m_Parent, m_State, eQuickBuildState::RESETTING, LWOOBJID_EMPTY);
|
||||
|
||||
m_State = eQuickBuildState::RESETTING;
|
||||
m_StateDirty = true;
|
||||
m_Timer = 0.0f;
|
||||
m_TimerIncomplete = 0.0f;
|
||||
m_ShowResetEffect = false;
|
||||
SetState(eQuickBuildState::RESETTING);
|
||||
SetTimer(0.0f);
|
||||
SetIncompleteTimer(0.0f);
|
||||
SetShowResetEffect(false);
|
||||
m_DrainedImagination = 0;
|
||||
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
@@ -563,8 +542,7 @@ void QuickBuildComponent::CancelQuickBuild(Entity* const entity, const eQuickBui
|
||||
GameMessages::SendTerminateInteraction(m_Parent->GetObjectID(), eTerminateType::FROM_INTERACTION, m_Parent->GetObjectID());
|
||||
|
||||
// Now update the component itself
|
||||
m_State = eQuickBuildState::INCOMPLETE;
|
||||
m_StateDirty = true;
|
||||
SetState(eQuickBuildState::INCOMPLETE);
|
||||
|
||||
// Notify scripts and possible subscribers
|
||||
m_Parent->GetScript()->OnQuickBuildNotifyState(m_Parent, m_State);
|
||||
|
||||
@@ -218,6 +218,48 @@ public:
|
||||
* @param skipChecks whether or not to skip the check for the quickbuild not being completed
|
||||
*/
|
||||
void CancelQuickBuild(Entity* const builder, const eQuickBuildFailReason failReason, const bool skipChecks = false);
|
||||
|
||||
void SetState(const eQuickBuildState state) {
|
||||
if (m_State == state) return;
|
||||
m_State = state;
|
||||
m_StateDirty = true;
|
||||
}
|
||||
|
||||
void SetShowResetEffect(const bool value) {
|
||||
if (m_ShowResetEffect == value) return;
|
||||
m_ShowResetEffect = value;
|
||||
m_StateDirty = true;
|
||||
}
|
||||
|
||||
void SetActivator(Entity* const activator) {
|
||||
if (m_Activator == activator) return;
|
||||
m_Activator = activator;
|
||||
m_StateDirty = true;
|
||||
}
|
||||
|
||||
void SetTimer(const float value) {
|
||||
if (m_Timer == value) return;
|
||||
m_Timer = value;
|
||||
m_StateDirty = true;
|
||||
}
|
||||
|
||||
void ModifyTimer(const float value) {
|
||||
if (value == 0.0f) return;
|
||||
m_Timer += value;
|
||||
m_StateDirty = true;
|
||||
}
|
||||
|
||||
void SetIncompleteTimer(const float value) {
|
||||
if (m_TimerIncomplete == value) return;
|
||||
m_TimerIncomplete = value;
|
||||
m_StateDirty = true;
|
||||
}
|
||||
|
||||
void ModifyIncompleteTimer(const float value) {
|
||||
if (value == 0.0f) return;
|
||||
m_TimerIncomplete += value;
|
||||
m_StateDirty = true;
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* Whether or not the quickbuild state has been changed since we last serialized it.
|
||||
|
||||
@@ -285,7 +285,7 @@ void RacingControlComponent::OnRacingClientReady(Entity* player) {
|
||||
Game::entityManager->SerializeEntity(m_Parent);
|
||||
}
|
||||
|
||||
void RacingControlComponent::OnRequestDie(Entity* player) {
|
||||
void RacingControlComponent::OnRequestDie(Entity* player, const std::u16string& deathType) {
|
||||
// Sent by the client when they collide with something which should smash
|
||||
// them.
|
||||
|
||||
@@ -301,8 +301,9 @@ void RacingControlComponent::OnRequestDie(Entity* player) {
|
||||
|
||||
if (!racingPlayer.noSmashOnReload) {
|
||||
racingPlayer.smashedTimes++;
|
||||
LOG("Death type %s", GeneralUtils::UTF16ToWTF8(deathType).c_str());
|
||||
GameMessages::SendDie(vehicle, vehicle->GetObjectID(), LWOOBJID_EMPTY, true,
|
||||
eKillType::VIOLENT, u"", 0, 0, 90.0f, false, true, 0);
|
||||
eKillType::VIOLENT, deathType, 0, 0, 90.0f, false, true, 0);
|
||||
|
||||
auto* destroyableComponent = vehicle->GetComponent<DestroyableComponent>();
|
||||
uint32_t respawnImagination = 0;
|
||||
|
||||
@@ -135,7 +135,7 @@ public:
|
||||
/**
|
||||
* Invoked when the client says it should be smashed.
|
||||
*/
|
||||
void OnRequestDie(Entity* player);
|
||||
void OnRequestDie(Entity* player, const std::u16string& deathType = u"");
|
||||
|
||||
/**
|
||||
* Invoked when the player has finished respawning.
|
||||
|
||||
@@ -123,6 +123,11 @@ void SkillComponent::SyncPlayerProjectile(const LWOOBJID projectileId, RakNet::B
|
||||
behavior->Handle(sync_entry.context, bitStream, branch);
|
||||
|
||||
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) {
|
||||
@@ -132,6 +137,7 @@ void SkillComponent::RegisterPlayerProjectile(const LWOOBJID projectileId, Behav
|
||||
entry.branchContext = branch;
|
||||
entry.lot = lot;
|
||||
entry.id = projectileId;
|
||||
entry.skillId = context->skillID;
|
||||
|
||||
this->m_managedProjectiles.push_back(entry);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,8 @@ struct ProjectileSyncEntry {
|
||||
|
||||
BehaviorBranchContext branchContext{ 0, 0 };
|
||||
|
||||
int32_t skillId{ 0 };
|
||||
|
||||
explicit ProjectileSyncEntry();
|
||||
};
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
|
||||
}
|
||||
|
||||
case MessageType::Game::PLAYER_LOADED: {
|
||||
GameMessages::SendRestoreToPostLoadStats(entity, sysAddr);
|
||||
GameMessages::SendPlayerReady(entity, sysAddr);
|
||||
entity->SetPlayerReadyForUpdates();
|
||||
|
||||
auto* ghostComponent = entity->GetComponent<GhostComponent>();
|
||||
@@ -135,6 +135,8 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
|
||||
}
|
||||
}
|
||||
|
||||
GameMessages::SendRestoreToPostLoadStats(entity, sysAddr);
|
||||
|
||||
auto* destroyable = entity->GetComponent<DestroyableComponent>();
|
||||
destroyable->SetImagination(destroyable->GetImagination());
|
||||
Game::entityManager->SerializeEntity(entity);
|
||||
@@ -182,7 +184,6 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
|
||||
LOG("Player %s (%llu) loaded.", entity->GetCharacter()->GetName().c_str(), entity->GetObjectID());
|
||||
|
||||
// After we've done our thing, tell the client they're ready
|
||||
GameMessages::SendPlayerReady(entity, sysAddr);
|
||||
GameMessages::SendPlayerReady(Game::zoneManager->GetZoneControlObject(), sysAddr);
|
||||
|
||||
if (Game::config->GetValue("allow_players_to_skip_cinematics") != "1"
|
||||
@@ -703,6 +704,12 @@ void GameMessageHandler::HandleMessage(RakNet::BitStream& inStream, const System
|
||||
case MessageType::Game::UPDATE_INVENTORY_GROUP_CONTENTS:
|
||||
GameMessages::HandleUpdateInventoryGroupContents(inStream, entity, sysAddr);
|
||||
break;
|
||||
case MessageType::Game::SHOOTING_GALLERY_FIRE: {
|
||||
GameMessages::ShootingGalleryFire fire{};
|
||||
fire.Deserialize(inStream);
|
||||
fire.Handle(*entity, sysAddr);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_DEBUG("Received Unknown GM with ID: %4i, %s", messageID, StringifiedEnum::ToString(messageID).data());
|
||||
|
||||
@@ -48,8 +48,6 @@
|
||||
#include <chrono>
|
||||
#include "RakString.h"
|
||||
|
||||
#include "httplib.h" //sorry not sorry.
|
||||
|
||||
//CDB includes:
|
||||
#include "CDClientManager.h"
|
||||
#include "CDEmoteTable.h"
|
||||
@@ -845,8 +843,10 @@ void GameMessages::SendDieNoImplCode(Entity* entity, const LWOOBJID& killerID, c
|
||||
|
||||
bitStream.Write(entity->GetObjectID());
|
||||
bitStream.Write(MessageType::Game::DIE);
|
||||
|
||||
bitStream.Write(bClientDeath);
|
||||
bitStream.Write(bSpawnLoot);
|
||||
bitStream.Write<uint32_t>(deathType.size());
|
||||
bitStream.Write(deathType);
|
||||
bitStream.Write(directionRelative_AngleXZ);
|
||||
bitStream.Write(directionRelative_AngleY);
|
||||
@@ -856,7 +856,10 @@ void GameMessages::SendDieNoImplCode(Entity* entity, const LWOOBJID& killerID, c
|
||||
if (killType != eKillType::VIOLENT) bitStream.Write(killType);
|
||||
|
||||
bitStream.Write(killerID);
|
||||
bitStream.Write(lootOwnerID);
|
||||
bitStream.Write(lootOwnerID != LWOOBJID_EMPTY);
|
||||
if (lootOwnerID != LWOOBJID_EMPTY) {
|
||||
bitStream.Write(lootOwnerID);
|
||||
}
|
||||
|
||||
SEND_PACKET_BROADCAST;
|
||||
}
|
||||
@@ -968,6 +971,8 @@ void GameMessages::SendResurrect(Entity* entity) {
|
||||
// and just make sure the client has time to be ready.
|
||||
constexpr float respawnTime = 3.66700005531311f + 0.5f;
|
||||
entity->AddCallbackTimer(respawnTime, [=]() {
|
||||
GameMessages::PlayerResurrectionFinished msg;
|
||||
entity->NotifyPlayerResurrectionFinished(msg);
|
||||
auto* destroyableComponent = entity->GetComponent<DestroyableComponent>();
|
||||
|
||||
if (destroyableComponent != nullptr && entity->GetLOT() == 1) {
|
||||
@@ -6395,4 +6400,35 @@ namespace GameMessages {
|
||||
bitStream.Write(targetPosition.y);
|
||||
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;
|
||||
void Send(const SystemAddress& sysAddr) 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;
|
||||
LWOOBJID target{ LWOOBJID_EMPTY };
|
||||
};
|
||||
@@ -727,6 +729,46 @@ namespace GameMessages {
|
||||
ConfigureRacingControl() : GameMsg(MessageType::Game::CONFIGURE_RACING_CONTROL) {}
|
||||
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{};
|
||||
};
|
||||
|
||||
struct ChildLoaded : public GameMsg {
|
||||
ChildLoaded() : GameMsg(MessageType::Game::CHILD_LOADED) {}
|
||||
|
||||
LOT templateID{};
|
||||
LWOOBJID childID{};
|
||||
};
|
||||
|
||||
struct PlayerResurrectionFinished : public GameMsg {
|
||||
PlayerResurrectionFinished() : GameMsg(MessageType::Game::PLAYER_RESURRECTION_FINISHED) {}
|
||||
};
|
||||
};
|
||||
|
||||
#endif // GAMEMESSAGES_H
|
||||
|
||||
@@ -62,6 +62,14 @@ std::map<uint32_t, std::string> activeSessions;
|
||||
SystemAddress authServerMasterPeerSysAddr;
|
||||
SystemAddress chatServerMasterPeerSysAddr;
|
||||
|
||||
int GenerateBCryptPassword(const std::string& password, const int workFactor, char salt[BCRYPT_HASHSIZE], char hash[BCRYPT_HASHSIZE]) {
|
||||
int32_t bcryptState = ::bcrypt_gensalt(workFactor, salt);
|
||||
assert(bcryptState == 0);
|
||||
bcryptState = ::bcrypt_hashpw(password.c_str(), salt, hash);
|
||||
assert(bcryptState == 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
constexpr uint32_t masterFramerate = mediumFramerate;
|
||||
constexpr uint32_t masterFrameDelta = mediumFrameDelta;
|
||||
@@ -94,7 +102,7 @@ int main(int argc, char** argv) {
|
||||
std::string(folder) +
|
||||
") folder from your download to the binary directory or re-run cmake.";
|
||||
LOG("%s", msg.c_str());
|
||||
// toss an error box up for windows users running the download
|
||||
// toss an error box up for windows users running the download
|
||||
#ifdef DARKFLAME_PLATFORM_WIN32
|
||||
MessageBoxA(nullptr, msg.c_str(), "Missing Folder", MB_OK | MB_ICONERROR);
|
||||
#endif
|
||||
@@ -238,10 +246,7 @@ int main(int argc, char** argv) {
|
||||
// Regenerate hash based on new password
|
||||
char salt[BCRYPT_HASHSIZE];
|
||||
char hash[BCRYPT_HASHSIZE];
|
||||
int32_t bcryptState = ::bcrypt_gensalt(12, salt);
|
||||
assert(bcryptState == 0);
|
||||
bcryptState = ::bcrypt_hashpw(password.c_str(), salt, hash);
|
||||
assert(bcryptState == 0);
|
||||
assert(GenerateBCryptPassword(password, 12, salt, hash) == 0);
|
||||
|
||||
Database::Get()->UpdateAccountPassword(accountId->id, std::string(hash, BCRYPT_HASHSIZE));
|
||||
|
||||
@@ -279,10 +284,7 @@ int main(int argc, char** argv) {
|
||||
//Generate new hash for bcrypt
|
||||
char salt[BCRYPT_HASHSIZE];
|
||||
char hash[BCRYPT_HASHSIZE];
|
||||
int32_t bcryptState = ::bcrypt_gensalt(12, salt);
|
||||
assert(bcryptState == 0);
|
||||
bcryptState = ::bcrypt_hashpw(password.c_str(), salt, hash);
|
||||
assert(bcryptState == 0);
|
||||
assert(GenerateBCryptPassword(password, 12, salt, hash) == 0);
|
||||
|
||||
//Create account
|
||||
try {
|
||||
@@ -318,15 +320,24 @@ int main(int argc, char** argv) {
|
||||
const auto externalIPString = Game::config->GetValue("external_ip");
|
||||
if (!externalIPString.empty()) ourIP = externalIPString;
|
||||
|
||||
Game::server = new dServer(ourIP, ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, &Game::lastSignal);
|
||||
char salt[BCRYPT_HASHSIZE];
|
||||
char hash[BCRYPT_HASHSIZE];
|
||||
const auto& cfgPassword = Game::config->GetValue("master_password");
|
||||
GenerateBCryptPassword(!cfgPassword.empty() ? cfgPassword : "3.25DARKFLAME1", 13, salt, hash);
|
||||
|
||||
Game::server = new dServer(ourIP, ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, &Game::lastSignal, hash);
|
||||
|
||||
std::string master_server_ip = "localhost";
|
||||
const auto masterServerIPString = Game::config->GetValue("master_ip");
|
||||
if (!masterServerIPString.empty()) master_server_ip = masterServerIPString;
|
||||
|
||||
if (master_server_ip == "") master_server_ip = Game::server->GetIP();
|
||||
IServers::MasterInfo info;
|
||||
info.ip = master_server_ip;
|
||||
info.port = Game::server->GetPort();
|
||||
info.password = hash;
|
||||
|
||||
Database::Get()->SetMasterIp(master_server_ip, Game::server->GetPort());
|
||||
Database::Get()->SetMasterInfo(info);
|
||||
|
||||
//Create additional objects here:
|
||||
PersistentIDManager::Initialize();
|
||||
|
||||
@@ -4,68 +4,146 @@
|
||||
#include "Game.h"
|
||||
#include "BinaryPathFinder.h"
|
||||
|
||||
void StartChatServer() {
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#include <handleapi.h>
|
||||
#include <processthreadsapi.h>
|
||||
|
||||
namespace {
|
||||
const auto startup = STARTUPINFOW{
|
||||
.cb = sizeof(STARTUPINFOW),
|
||||
.lpReserved = nullptr,
|
||||
.lpDesktop = nullptr,
|
||||
.lpTitle = nullptr,
|
||||
.dwX = 0,
|
||||
.dwY = 0,
|
||||
.dwXSize = 0,
|
||||
.dwYSize = 0,
|
||||
.dwXCountChars = 0,
|
||||
.dwYCountChars = 0,
|
||||
.dwFillAttribute = 0,
|
||||
.dwFlags = 0,
|
||||
.wShowWindow = 0,
|
||||
.cbReserved2 = 0,
|
||||
.lpReserved2 = nullptr,
|
||||
.hStdInput = INVALID_HANDLE_VALUE,
|
||||
.hStdOutput = INVALID_HANDLE_VALUE,
|
||||
.hStdError = INVALID_HANDLE_VALUE,
|
||||
};
|
||||
}
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
uint32_t StartChatServer() {
|
||||
if (Game::ShouldShutdown()) {
|
||||
LOG("Currently shutting down. Chat will not be restarted.");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
auto chat_path = BinaryPathFinder::GetBinaryDir() / "ChatServer";
|
||||
#ifdef _WIN32
|
||||
chat_path.replace_extension(".exe");
|
||||
auto chat_startup = startup;
|
||||
auto chat_info = PROCESS_INFORMATION{};
|
||||
if (!CreateProcessW(chat_path.wstring().data(), chat_path.wstring().data(),
|
||||
nullptr, nullptr, false, 0, nullptr, nullptr,
|
||||
&chat_startup, &chat_info))
|
||||
{
|
||||
LOG("Failed to launch ChatServer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get pid and close unused handles
|
||||
auto chat_pid = chat_info.dwProcessId;
|
||||
CloseHandle(chat_info.hProcess);
|
||||
CloseHandle(chat_info.hThread);
|
||||
#else // *nix systems
|
||||
const auto chat_pid = fork();
|
||||
if (chat_pid < 0) {
|
||||
LOG("Failed to launch ChatServer");
|
||||
return 0;
|
||||
} else if (chat_pid == 0) {
|
||||
// We are the child process
|
||||
execl(chat_path.string().c_str(), chat_path.string().c_str(), nullptr);
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
//macOS doesn't need sudo to run on ports < 1024
|
||||
auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str());
|
||||
#elif _WIN32
|
||||
auto result = system(("start /B " + (BinaryPathFinder::GetBinaryDir() / "ChatServer.exe").string()).c_str());
|
||||
#else
|
||||
if (std::atoi(Game::config->GetValue("use_sudo_chat").c_str())) {
|
||||
auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str());
|
||||
} else {
|
||||
auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str());
|
||||
}
|
||||
#endif
|
||||
LOG("ChatServer PID is %d", chat_pid);
|
||||
return chat_pid;
|
||||
}
|
||||
|
||||
void StartAuthServer() {
|
||||
uint32_t StartAuthServer() {
|
||||
if (Game::ShouldShutdown()) {
|
||||
LOG("Currently shutting down. Auth will not be restarted.");
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str());
|
||||
#elif _WIN32
|
||||
auto result = system(("start /B " + (BinaryPathFinder::GetBinaryDir() / "AuthServer.exe").string()).c_str());
|
||||
#else
|
||||
if (std::atoi(Game::config->GetValue("use_sudo_auth").c_str())) {
|
||||
auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str());
|
||||
} else {
|
||||
auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void StartWorldServer(LWOMAPID mapID, uint16_t port, LWOINSTANCEID lastInstanceID, int maxPlayers, LWOCLONEID cloneID) {
|
||||
auto auth_path = BinaryPathFinder::GetBinaryDir() / "AuthServer";
|
||||
#ifdef _WIN32
|
||||
std::string cmd = "start /B " + (BinaryPathFinder::GetBinaryDir() / "WorldServer.exe").string() + " -zone ";
|
||||
#else
|
||||
std::string cmd;
|
||||
if (std::atoi(Game::config->GetValue("use_sudo_world").c_str())) {
|
||||
cmd = "sudo " + (BinaryPathFinder::GetBinaryDir() / "WorldServer").string() + " -zone ";
|
||||
} else {
|
||||
cmd = (BinaryPathFinder::GetBinaryDir() / "WorldServer").string() + " -zone ";
|
||||
auth_path.replace_extension(".exe");
|
||||
auto auth_startup = startup;
|
||||
auto auth_info = PROCESS_INFORMATION{};
|
||||
if (!CreateProcessW(auth_path.wstring().data(), auth_path.wstring().data(),
|
||||
nullptr, nullptr, false, 0, nullptr, nullptr,
|
||||
&auth_startup, &auth_info))
|
||||
{
|
||||
LOG("Failed to launch AuthServer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get pid and close unused handles
|
||||
auto auth_pid = auth_info.dwProcessId;
|
||||
CloseHandle(auth_info.hProcess);
|
||||
CloseHandle(auth_info.hThread);
|
||||
#else // *nix systems
|
||||
const auto auth_pid = fork();
|
||||
if (auth_pid < 0) {
|
||||
LOG("Failed to launch AuthServer");
|
||||
return 0;
|
||||
} else if (auth_pid == 0) {
|
||||
// We are the child process
|
||||
execl(auth_path.string().c_str(), auth_path.string().c_str(), nullptr);
|
||||
}
|
||||
#endif
|
||||
|
||||
cmd.append(std::to_string(mapID));
|
||||
cmd.append(" -port ");
|
||||
cmd.append(std::to_string(port));
|
||||
cmd.append(" -instance ");
|
||||
cmd.append(std::to_string(lastInstanceID));
|
||||
cmd.append(" -maxclients ");
|
||||
cmd.append(std::to_string(maxPlayers));
|
||||
cmd.append(" -clone ");
|
||||
cmd.append(std::to_string(cloneID));
|
||||
|
||||
#ifndef _WIN32
|
||||
cmd.append("&"); //Sends our next process to the background on Linux
|
||||
#endif
|
||||
|
||||
auto ret = system(cmd.c_str());
|
||||
LOG("AuthServer PID is %d", auth_pid);
|
||||
return auth_pid;
|
||||
}
|
||||
|
||||
uint32_t StartWorldServer(LWOMAPID mapID, uint16_t port, LWOINSTANCEID lastInstanceID, int maxPlayers, LWOCLONEID cloneID) {
|
||||
auto world_path = BinaryPathFinder::GetBinaryDir() / "WorldServer";
|
||||
#ifdef _WIN32
|
||||
world_path.replace_extension(".exe");
|
||||
auto cmd = world_path.wstring() + L" -zone " + std::to_wstring(mapID) + L" -port " + std::to_wstring(port) +
|
||||
L" -instance " + std::to_wstring(lastInstanceID) + L" -maxclients " + std::to_wstring(maxPlayers) +
|
||||
L" -clone " + std::to_wstring(cloneID);
|
||||
|
||||
auto world_startup = startup;
|
||||
auto world_info = PROCESS_INFORMATION{};
|
||||
if (!CreateProcessW(world_path.wstring().data(), cmd.data(),
|
||||
nullptr, nullptr, false, 0, nullptr, nullptr,
|
||||
&world_startup, &world_info))
|
||||
{
|
||||
LOG("Failed to launch WorldServer");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get pid and close unused handles
|
||||
auto world_pid = world_info.dwProcessId;
|
||||
CloseHandle(world_info.hProcess);
|
||||
CloseHandle(world_info.hThread);
|
||||
#else
|
||||
const auto world_pid = fork();
|
||||
if (world_pid < 0) {
|
||||
LOG("Failed to launch WorldServer");
|
||||
return 0;
|
||||
} else if (world_pid == 0) {
|
||||
// We are the child process
|
||||
execl(world_path.string().c_str(), world_path.string().c_str(),
|
||||
"-zone", std::to_string(mapID).c_str(),
|
||||
"-port", std::to_string(port).c_str(),
|
||||
"-instance", std::to_string(lastInstanceID).c_str(),
|
||||
"-maxclients", std::to_string(maxPlayers).c_str(),
|
||||
"-clone", std::to_string(cloneID).c_str(), nullptr);
|
||||
}
|
||||
#endif
|
||||
LOG("WorldServer PID is %d", world_pid);
|
||||
return world_pid;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#pragma once
|
||||
#include "dCommonVars.h"
|
||||
|
||||
void StartAuthServer();
|
||||
void StartChatServer();
|
||||
void StartWorldServer(LWOMAPID mapID, uint16_t port, LWOINSTANCEID lastInstanceID, int maxPlayers, LWOCLONEID cloneID);
|
||||
uint32_t StartAuthServer();
|
||||
uint32_t StartChatServer();
|
||||
uint32_t StartWorldServer(LWOMAPID mapID, uint16_t port, LWOINSTANCEID lastInstanceID, int maxPlayers, LWOCLONEID cloneID);
|
||||
|
||||
@@ -3,4 +3,3 @@
|
||||
#include "RakPeer.h"
|
||||
|
||||
#define NET_PASSWORD_EXTERNAL "3.25 ND1"
|
||||
#define NET_PASSWORD_INTERNAL "3.25 DARKFLAME1"
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "MessageType/Server.h"
|
||||
#include "MessageType/Master.h"
|
||||
|
||||
#include "BinaryPathFinder.h"
|
||||
#include "BitStreamUtils.h"
|
||||
#include "MasterPackets.h"
|
||||
#include "ZoneInstanceManager.h"
|
||||
@@ -39,7 +40,21 @@ public:
|
||||
}
|
||||
} ReceiveDownloadCompleteCB;
|
||||
|
||||
dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, Logger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, Game::signal_t* lastSignal, unsigned int zoneID) {
|
||||
dServer::dServer(
|
||||
const std::string& ip,
|
||||
int port,
|
||||
int instanceID,
|
||||
int maxConnections,
|
||||
bool isInternal,
|
||||
bool useEncryption,
|
||||
Logger* logger,
|
||||
const std::string masterIP,
|
||||
int masterPort,
|
||||
ServerType serverType,
|
||||
dConfig* config,
|
||||
Game::signal_t* lastSignal,
|
||||
const std::string& masterPassword,
|
||||
unsigned int zoneID) {
|
||||
mIP = ip;
|
||||
mPort = port;
|
||||
mZoneID = zoneID;
|
||||
@@ -55,6 +70,7 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect
|
||||
mReplicaManager = nullptr;
|
||||
mServerType = serverType;
|
||||
mConfig = config;
|
||||
mMasterPassword = masterPassword;
|
||||
mShouldShutdown = lastSignal;
|
||||
//Attempt to start our server here:
|
||||
mIsOkay = Startup();
|
||||
@@ -68,7 +84,16 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect
|
||||
LOG("%s Server is listening on %s:%i with encryption: %i", StringifiedEnum::ToString(serverType).data(), ip.c_str(), port, int(useEncryption));
|
||||
else
|
||||
LOG("%s Server is listening on %s:%i with encryption: %i, running zone %i / %i", StringifiedEnum::ToString(serverType).data(), ip.c_str(), port, int(useEncryption), zoneID, instanceID);
|
||||
} else { LOG("FAILED TO START SERVER ON IP/PORT: %s:%i", ip.c_str(), port); return; }
|
||||
} else {
|
||||
LOG("FAILED TO START SERVER ON IP/PORT: %s:%i", ip.c_str(), port);
|
||||
#ifdef DARKFLAME_PLATFORM_LINUX
|
||||
if (mServerType == ServerType::Auth) {
|
||||
const auto cwd = BinaryPathFinder::GetBinaryDir();
|
||||
LOG("Try running the following command before launching again:\n sudo setcap 'cap_net_bind_service=+ep' \"%s/AuthServer\"", cwd.string().c_str());
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
mLogger->SetLogToConsole(prevLogSetting);
|
||||
|
||||
@@ -109,20 +134,23 @@ Packet* dServer::ReceiveFromMaster() {
|
||||
if (packet) {
|
||||
if (packet->length < 1) { mMasterPeer->DeallocatePacket(packet); return nullptr; }
|
||||
|
||||
if (packet->data[0] == ID_DISCONNECTION_NOTIFICATION || packet->data[0] == ID_CONNECTION_LOST) {
|
||||
switch (packet->data[0]) {
|
||||
case ID_DISCONNECTION_NOTIFICATION:
|
||||
[[fallthrough]];
|
||||
case ID_CONNECTION_LOST: {
|
||||
LOG("Lost our connection to master, shutting DOWN!");
|
||||
mMasterConnectionActive = false;
|
||||
//ConnectToMaster(); //We'll just shut down now
|
||||
// ConnectToMaster(); // We'll just shut down now
|
||||
break;
|
||||
}
|
||||
|
||||
if (packet->data[0] == ID_CONNECTION_REQUEST_ACCEPTED) {
|
||||
case ID_CONNECTION_REQUEST_ACCEPTED: {
|
||||
LOG("Established connection to master, zone (%i), instance (%i)", this->GetZoneID(), this->GetInstanceID());
|
||||
mMasterConnectionActive = true;
|
||||
mMasterSystemAddress = packet->systemAddress;
|
||||
MasterPackets::SendServerInfo(this, packet);
|
||||
break;
|
||||
}
|
||||
|
||||
if (packet->data[0] == ID_USER_PACKET_ENUM) {
|
||||
case ID_USER_PACKET_ENUM: {
|
||||
if (static_cast<eConnectionType>(packet->data[1]) == eConnectionType::MASTER) {
|
||||
switch (static_cast<MessageType::Master>(packet->data[3])) {
|
||||
case MessageType::Master::REQUEST_ZONE_TRANSFER_RESPONSE: {
|
||||
@@ -133,12 +161,13 @@ Packet* dServer::ReceiveFromMaster() {
|
||||
*mShouldShutdown = -2;
|
||||
break;
|
||||
|
||||
//When we handle these packets in World instead dServer, we just return the packet's pointer.
|
||||
// When we handle these packets in World instead dServer, we just return the packet's pointer.
|
||||
default:
|
||||
|
||||
return packet;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mMasterPeer->DeallocatePacket(packet);
|
||||
@@ -189,11 +218,11 @@ bool dServer::Startup() {
|
||||
if (!mPeer->Startup(mMaxConnections, 10, &mSocketDescriptor, 1)) return false;
|
||||
|
||||
if (mIsInternal) {
|
||||
mPeer->SetIncomingPassword("3.25 DARKFLAME1", 15);
|
||||
mPeer->SetIncomingPassword(mMasterPassword.c_str(), mMasterPassword.size());
|
||||
} else {
|
||||
UpdateBandwidthLimit();
|
||||
UpdateMaximumMtuSize();
|
||||
mPeer->SetIncomingPassword("3.25 ND1", 8);
|
||||
mPeer->SetIncomingPassword(NET_PASSWORD_EXTERNAL, strnlen(NET_PASSWORD_EXTERNAL, sizeof(NET_PASSWORD_EXTERNAL)));
|
||||
}
|
||||
|
||||
mPeer->SetMaximumIncomingConnections(mMaxConnections);
|
||||
@@ -243,7 +272,7 @@ void dServer::SetupForMasterConnection() {
|
||||
|
||||
bool dServer::ConnectToMaster() {
|
||||
//LOG("Connection to Master %s:%d", mMasterIP.c_str(), mMasterPort);
|
||||
return mMasterPeer->Connect(mMasterIP.c_str(), mMasterPort, "3.25 DARKFLAME1", 15);
|
||||
return mMasterPeer->Connect(mMasterIP.c_str(), mMasterPort, mMasterPassword.c_str(), mMasterPassword.size());
|
||||
}
|
||||
|
||||
void dServer::UpdateReplica() {
|
||||
|
||||
@@ -46,6 +46,7 @@ public:
|
||||
ServerType serverType,
|
||||
dConfig* config,
|
||||
Game::signal_t* shouldShutdown,
|
||||
const std::string& masterPassword,
|
||||
unsigned int zoneID = 0);
|
||||
~dServer();
|
||||
|
||||
@@ -121,4 +122,5 @@ protected:
|
||||
std::string mMasterIP;
|
||||
int mMasterPort;
|
||||
std::chrono::steady_clock::time_point mStartTime = std::chrono::steady_clock::now();
|
||||
std::string mMasterPassword;
|
||||
};
|
||||
|
||||
@@ -64,21 +64,22 @@ void AmSkullkinTower::SpawnLegs(Entity* self, const std::string& loc) {
|
||||
|
||||
info.rot = NiQuaternion::LookAt(info.pos, self->GetPosition());
|
||||
|
||||
auto* entity = Game::entityManager->CreateEntity(info);
|
||||
auto* entity = Game::entityManager->CreateEntity(info, nullptr, self);
|
||||
|
||||
Game::entityManager->ConstructEntity(entity);
|
||||
|
||||
OnChildLoaded(self, entity);
|
||||
}
|
||||
|
||||
void AmSkullkinTower::OnChildLoaded(Entity* self, Entity* child) {
|
||||
auto legTable = self->GetVar<std::vector<LWOOBJID>>(u"legTable");
|
||||
void AmSkullkinTower::OnChildLoaded(Entity& self, GameMessages::ChildLoaded& childLoaded) {
|
||||
auto legTable = self.GetVar<std::vector<LWOOBJID>>(u"legTable");
|
||||
|
||||
legTable.push_back(child->GetObjectID());
|
||||
legTable.push_back(childLoaded.childID);
|
||||
|
||||
self->SetVar(u"legTable", legTable);
|
||||
self.SetVar(u"legTable", legTable);
|
||||
|
||||
const auto selfID = self->GetObjectID();
|
||||
const auto selfID = self.GetObjectID();
|
||||
auto* const child = Game::entityManager->GetEntity(childLoaded.childID);
|
||||
|
||||
if (!child) return;
|
||||
|
||||
child->AddDieCallback([this, selfID, child]() {
|
||||
auto* self = Game::entityManager->GetEntity(selfID);
|
||||
|
||||
@@ -8,7 +8,7 @@ public:
|
||||
|
||||
void SpawnLegs(Entity* self, const std::string& loc);
|
||||
|
||||
void OnChildLoaded(Entity* self, Entity* child);
|
||||
void OnChildLoaded(Entity& self, GameMessages::ChildLoaded& childLoaded) override;
|
||||
|
||||
void NotifyDie(Entity* self, Entity* other, Entity* killer);
|
||||
|
||||
|
||||
@@ -77,8 +77,6 @@ void QbSpawner::OnTimerDone(Entity* self, std::string timerName) {
|
||||
|
||||
auto* child = Game::entityManager->CreateEntity(info, nullptr, self);
|
||||
Game::entityManager->ConstructEntity(child);
|
||||
|
||||
OnChildLoaded(self, child);
|
||||
} else {
|
||||
auto* mob = Game::entityManager->GetEntity(mobTable[i]);
|
||||
AggroTargetObject(self, mob);
|
||||
@@ -88,16 +86,19 @@ void QbSpawner::OnTimerDone(Entity* self, std::string timerName) {
|
||||
}
|
||||
}
|
||||
|
||||
void QbSpawner::OnChildLoaded(Entity* self, Entity* child) {
|
||||
auto mobTable = self->GetVar<std::vector<LWOOBJID>>(u"mobTable");
|
||||
void QbSpawner::OnChildLoaded(Entity& self, GameMessages::ChildLoaded& childLoaded) {
|
||||
auto* const child = Game::entityManager->GetEntity(childLoaded.childID);
|
||||
if (!child) return;
|
||||
|
||||
auto mobTable = self.GetVar<std::vector<LWOOBJID>>(u"mobTable");
|
||||
auto tableLoc = child->GetVar<int>(u"mobTableLoc");
|
||||
|
||||
mobTable[tableLoc] = child->GetObjectID();
|
||||
self->SetVar<std::vector<LWOOBJID>>(u"mobTable", mobTable);
|
||||
self.SetVar<std::vector<LWOOBJID>>(u"mobTable", mobTable);
|
||||
|
||||
AggroTargetObject(self, child);
|
||||
AggroTargetObject(&self, child);
|
||||
|
||||
const auto selfID = self->GetObjectID();
|
||||
const auto selfID = self.GetObjectID();
|
||||
|
||||
child->AddDieCallback([this, selfID, child]() {
|
||||
auto* self = Game::entityManager->GetEntity(selfID);
|
||||
|
||||
@@ -6,7 +6,7 @@ public:
|
||||
void OnStartup(Entity* self) override;
|
||||
void OnFireEventServerSide(Entity* self, Entity* sender, std::string args, int32_t param1, int32_t param2, int32_t param3) override;
|
||||
void OnTimerDone(Entity* self, std::string timerName) override;
|
||||
void OnChildLoaded(Entity* self, Entity* child);
|
||||
void OnChildLoaded(Entity& self, GameMessages::ChildLoaded& childLoaded) override;
|
||||
void OnChildRemoved(Entity* self, Entity* child);
|
||||
void AggroTargetObject(Entity* self, Entity* enemy);
|
||||
private:
|
||||
|
||||
@@ -10,49 +10,38 @@ void NsLegoClubDoor::OnStartup(Entity* self) {
|
||||
self->SetVar(u"teleportString", m_TeleportString);
|
||||
self->SetVar(u"spawnPoint", m_SpawnPoint);
|
||||
|
||||
args = {};
|
||||
teleportArgs.Reset();
|
||||
|
||||
args.Insert("callbackClient", std::to_string(self->GetObjectID()));
|
||||
args.Insert("strIdentifier", "choiceDoor");
|
||||
args.Insert("title", "%[UI_CHOICE_DESTINATION]");
|
||||
teleportArgs.Insert("callbackClient", std::to_string(self->GetObjectID()));
|
||||
teleportArgs.Insert("strIdentifier", "choiceDoor");
|
||||
teleportArgs.Insert("title", "%[UI_CHOICE_DESTINATION]");
|
||||
|
||||
AMFArrayValue* choiceOptions = args.InsertArray("options");
|
||||
auto& choiceOptions = *teleportArgs.InsertArray("options");
|
||||
|
||||
{
|
||||
AMFArrayValue* nsArgs = choiceOptions->PushArray();
|
||||
auto& nsArgs = *choiceOptions.PushArray();
|
||||
|
||||
nsArgs->Insert("image", "textures/ui/zone_thumnails/Nimbus_Station.dds");
|
||||
nsArgs->Insert("caption", "%[UI_CHOICE_NS]");
|
||||
nsArgs->Insert("identifier", "zoneID_1200");
|
||||
nsArgs->Insert("tooltipText", "%[UI_CHOICE_NS_HOVER]");
|
||||
nsArgs.Insert("image", "textures/ui/zone_thumnails/Nimbus_Station.dds");
|
||||
nsArgs.Insert("caption", "%[UI_CHOICE_NS]");
|
||||
nsArgs.Insert("identifier", "zoneID_1200");
|
||||
nsArgs.Insert("tooltipText", "%[UI_CHOICE_NS_HOVER]");
|
||||
}
|
||||
|
||||
{
|
||||
AMFArrayValue* ntArgs = choiceOptions->PushArray();
|
||||
auto& ntArgs = *choiceOptions.PushArray();
|
||||
|
||||
ntArgs->Insert("image", "textures/ui/zone_thumnails/Nexus_Tower.dds");
|
||||
ntArgs->Insert("caption", "%[UI_CHOICE_NT]");
|
||||
ntArgs->Insert("identifier", "zoneID_1900");
|
||||
ntArgs->Insert("tooltipText", "%[UI_CHOICE_NT_HOVER]");
|
||||
ntArgs.Insert("image", "textures/ui/zone_thumnails/Nexus_Tower.dds");
|
||||
ntArgs.Insert("caption", "%[UI_CHOICE_NT]");
|
||||
ntArgs.Insert("identifier", "zoneID_1900");
|
||||
ntArgs.Insert("tooltipText", "%[UI_CHOICE_NT_HOVER]");
|
||||
}
|
||||
|
||||
options = choiceOptions;
|
||||
}
|
||||
|
||||
void NsLegoClubDoor::OnUse(Entity* self, Entity* user) {
|
||||
auto* player = user;
|
||||
|
||||
if (CheckChoice(self, player)) {
|
||||
AMFArrayValue multiArgs;
|
||||
|
||||
multiArgs.Insert("callbackClient", std::to_string(self->GetObjectID()));
|
||||
multiArgs.Insert("strIdentifier", "choiceDoor");
|
||||
multiArgs.Insert("title", "%[UI_CHOICE_DESTINATION]");
|
||||
multiArgs.Insert("options", static_cast<AMFBaseValue*>(options));
|
||||
|
||||
GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", multiArgs);
|
||||
|
||||
multiArgs.Remove("options", false); // We do not want the local amf to delete the options!
|
||||
GameMessages::SendUIMessageServerToSingleClient(player, player->GetSystemAddress(), "QueueChoiceBox", teleportArgs);
|
||||
} else if (self->GetVar<int32_t>(u"currentZone") != m_ChoiceZoneID) {
|
||||
AMFArrayValue multiArgs;
|
||||
multiArgs.Insert("state", "Lobby");
|
||||
|
||||
@@ -19,6 +19,5 @@ private:
|
||||
std::string m_SpawnPoint = "NS_LEGO_Club";
|
||||
std::u16string m_TeleportAnim = u"lup-teleport";
|
||||
std::u16string m_TeleportString = u"ROCKET_TOOLTIP_USE_THE_GATEWAY_TO_TRAVEL_TO_LUP_WORLD";
|
||||
AMFArrayValue args = {};
|
||||
AMFArrayValue* options = {};
|
||||
AMFArrayValue teleportArgs{};
|
||||
};
|
||||
|
||||
@@ -91,7 +91,7 @@ void NtCombatChallengeServer::SpawnTargetDummy(Entity* self) {
|
||||
info.rot = self->GetRotation();
|
||||
info.settings = { new LDFData<std::string>(u"custom_script_server", "scripts\\02_server\\Map\\NT\\L_NT_COMBAT_CHALLENGE_DUMMY.lua") };
|
||||
|
||||
auto* dummy = Game::entityManager->CreateEntity(info);
|
||||
auto* dummy = Game::entityManager->CreateEntity(info, nullptr, self);
|
||||
|
||||
dummy->SetVar(u"challengeObjectID", self->GetObjectID());
|
||||
|
||||
@@ -104,26 +104,18 @@ void NtCombatChallengeServer::SetAttackImmunity(LWOOBJID objID, bool bTurnOn) {
|
||||
|
||||
}
|
||||
|
||||
void NtCombatChallengeServer::OnChildLoaded(Entity* self, Entity* child) {
|
||||
auto targetNumber = self->GetVar<int32_t>(u"TargetNumber");
|
||||
if (targetNumber == 0) targetNumber = 1;
|
||||
self->SetVar(u"TargetNumber", targetNumber + 1);
|
||||
void NtCombatChallengeServer::OnChildLoaded(Entity& self, GameMessages::ChildLoaded& childLoaded) {
|
||||
auto* const child = Game::entityManager->GetEntity(childLoaded.childID);
|
||||
|
||||
const auto playerID = self->GetVar<LWOOBJID>(u"playerID");
|
||||
|
||||
auto* player = Game::entityManager->GetEntity(playerID);
|
||||
|
||||
if (player == nullptr) {
|
||||
return;
|
||||
if (child) {
|
||||
child->SetRotation(NiQuaternion::FromEulerAngles(child->GetRotation().GetEulerAngles() += NiPoint3(0, PI, 0))); // rotate 180 degrees
|
||||
}
|
||||
|
||||
child->SetRotation(NiQuaternion::LookAt(child->GetPosition(), player->GetPosition()));
|
||||
|
||||
self->SetVar(u"currentTargetID", child->GetObjectID());
|
||||
self.SetVar(u"currentTargetID", child->GetObjectID());
|
||||
|
||||
Game::entityManager->SerializeEntity(child);
|
||||
|
||||
child->GetGroups().push_back("targets_" + std::to_string(self->GetObjectID()));
|
||||
child->GetGroups().push_back("targets_" + std::to_string(self.GetObjectID()));
|
||||
}
|
||||
|
||||
void NtCombatChallengeServer::ResetGame(Entity* self) {
|
||||
|
||||
@@ -12,7 +12,7 @@ public:
|
||||
void OnMessageBoxResponse(Entity* self, Entity* sender, int32_t button, const std::u16string& identifier, const std::u16string& userData) override;
|
||||
void SpawnTargetDummy(Entity* self);
|
||||
void SetAttackImmunity(LWOOBJID objID, bool bTurnOn);
|
||||
void OnChildLoaded(Entity* self, Entity* child);
|
||||
void OnChildLoaded(Entity& self, GameMessages::ChildLoaded& childLoaded) override;
|
||||
void ResetGame(Entity* self);
|
||||
void OnActivityTimerUpdate(Entity* self, float timeRemaining);
|
||||
void OnTimerDone(Entity* self, std::string timerName) override;
|
||||
|
||||
@@ -12,7 +12,7 @@ void VeBricksampleServer::OnUse(Entity* self, Entity* user) {
|
||||
auto* inventoryComponent = user->GetComponent<InventoryComponent>();
|
||||
|
||||
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")) {
|
||||
GameMessages::SendNotifyClientObject(brickEntity->GetObjectID(), u"Pickedup");
|
||||
|
||||
@@ -10,7 +10,7 @@ void VeMissionConsole::OnUse(Entity* self, Entity* user) {
|
||||
|
||||
auto* inventoryComponent = user->GetComponent<InventoryComponent>();
|
||||
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>
|
||||
|
||||
@@ -163,7 +163,7 @@ int32_t ActivityManager::GetGameID(Entity* self) const {
|
||||
|
||||
float_t ActivityManager::ActivityTimerGetRemainingTime(Entity* self, const std::string& timerName) const {
|
||||
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) {
|
||||
|
||||
@@ -294,6 +294,9 @@
|
||||
#include "ShardArmor.h"
|
||||
#include "TeslaPack.h"
|
||||
#include "StunImmunity.h"
|
||||
#include "GfRaceServer.h"
|
||||
#include "FvRaceServer.h"
|
||||
#include "VehicleDeathTriggerWaterServer.h"
|
||||
|
||||
// Survival scripts
|
||||
#include "AgSurvivalStromling.h"
|
||||
@@ -331,6 +334,8 @@
|
||||
#include "AgSpiderBossMessage.h"
|
||||
#include "GfRaceInstancer.h"
|
||||
#include "NsRaceServer.h"
|
||||
#include "TrialFactionArmorServer.h"
|
||||
#include "ImaginationBackPack.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -694,6 +699,11 @@ namespace {
|
||||
{"scripts\\ai\\AG\\L_AG_SPIDER_BOSS_MESSAGE.lua", []() {return new AgSpiderBossMessage();}},
|
||||
{"scripts\\ai\\GF\\L_GF_RACE_INSTANCER.lua", []() {return new GfRaceInstancer();}},
|
||||
{"scripts\\ai\\RACING\\TRACK_NS\\NS_RACE_SERVER.lua", []() {return new NsRaceServer();}},
|
||||
{"scripts\\ai\\RACING\\TRACK_GF\\GF_RACE_SERVER.lua", []() {return new GfRaceServer();}},
|
||||
{"scripts\\ai\\RACING\\TRACK_FV\\FV_RACE_SERVER.lua", []() {return new FvRaceServer();}},
|
||||
{"scripts\\ai\\RACING\\OBJECTS\\VEHICLE_DEATH_TRIGGER_WATER_SERVER.lua", []() {return new VehicleDeathTriggerWaterServer();}},
|
||||
{"scripts\\equipmenttriggers\\L_TRIAL_FACTION_ARMOR_SERVER.lua", []() {return new TrialFactionArmorServer();}},
|
||||
{"scripts\\equipmenttriggers\\ImaginationBackPack.lua", []() {return new ImaginationBackPack();}},
|
||||
|
||||
};
|
||||
|
||||
@@ -712,6 +722,12 @@ namespace {
|
||||
"scripts\\ai\\PETS\\PET_BLOCKER.lua",
|
||||
"scripts\\ai\\PETS\\PET_FLEA_MISSION.lua",
|
||||
"scripts\\ai\\ACT\\L_ACT_PET_INSTANCE_EXIT.lua",
|
||||
"scripts\\ai\\WILD\\L_WILD_GF_FROG.lua",
|
||||
"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_Robotanist.lua",
|
||||
"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_Seperator.lua",
|
||||
"scripts\\zone\\LUPs\\RobotCity Intro\\WBL_RCIntro_InfectedCitizen.lua",
|
||||
"scripts\\ai\\MINIGAME\\SIEGE\\OBJECTS\\ATTACKER_BOUNCER_SERVER.lua",
|
||||
"scripts\\ai\\AG\\L_AG_ZONE_PLAYER.lua",
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -186,6 +186,8 @@ namespace CppScripts {
|
||||
*/
|
||||
virtual void NotifyHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {};
|
||||
|
||||
virtual void NotifyPlayerResurrectionFinished(Entity& self, GameMessages::PlayerResurrectionFinished& msg) {};
|
||||
|
||||
/**
|
||||
* Invoked when a player has responsed to a mission.
|
||||
*
|
||||
@@ -357,6 +359,30 @@ namespace CppScripts {
|
||||
virtual void OnRequestActivityExit(Entity* sender, LWOOBJID player, bool canceled) {};
|
||||
|
||||
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) {};
|
||||
|
||||
/**
|
||||
* @brief Handles when a child is loaded
|
||||
*
|
||||
* @param self
|
||||
* @param fire The child info
|
||||
*/
|
||||
virtual void OnChildLoaded(Entity& self, GameMessages::ChildLoaded& childLoaded) {};
|
||||
};
|
||||
|
||||
Script* const GetScript(Entity* parent, const std::string& scriptName);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
set(DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS
|
||||
"CoilBackpackBase.cpp")
|
||||
"CoilBackpackBase.cpp"
|
||||
"ImaginationBackPack.cpp"
|
||||
"TrialFactionArmorServer.cpp")
|
||||
|
||||
add_library(dScriptsEquipmentTriggers OBJECT ${DSCRIPTS_SOURCES_EQUIPMENTTRIGGERSSCRIPTS})
|
||||
target_include_directories(dScriptsEquipmentTriggers PUBLIC ".")
|
||||
|
||||
22
dScripts/EquipmentTriggers/ImaginationBackPack.cpp
Normal file
22
dScripts/EquipmentTriggers/ImaginationBackPack.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include "ImaginationBackPack.h"
|
||||
|
||||
#include "SkillComponent.h"
|
||||
|
||||
void ImaginationBackPack::OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) {
|
||||
LOG("Subscribing to PlayerResurrectionFinished");
|
||||
itemOwner->Subscribe(itemObjId, this, "PlayerResurrectionFinished");
|
||||
}
|
||||
|
||||
void ImaginationBackPack::NotifyPlayerResurrectionFinished(Entity& self, GameMessages::PlayerResurrectionFinished& msg) {
|
||||
LOG("PlayerResurrectionFinished");
|
||||
auto* skillComponent = self.GetComponent<SkillComponent>();
|
||||
if (!skillComponent) return;
|
||||
LOG("Casting skill 1334");
|
||||
skillComponent->CastSkill(1334);
|
||||
}
|
||||
|
||||
void ImaginationBackPack::OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) {
|
||||
LOG("Unsubscribing from PlayerResurrectionFinished");
|
||||
itemOwner->Unsubscribe(itemObjId, "PlayerResurrectionFinished");
|
||||
}
|
||||
|
||||
13
dScripts/EquipmentTriggers/ImaginationBackPack.h
Normal file
13
dScripts/EquipmentTriggers/ImaginationBackPack.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef IMAGINATIONBACKPACK_H
|
||||
#define IMAGINATIONBACKPACK_H
|
||||
|
||||
#include "CppScripts.h"
|
||||
|
||||
class ImaginationBackPack : public CppScripts::Script {
|
||||
public:
|
||||
void OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) override;
|
||||
void NotifyPlayerResurrectionFinished(Entity& self, GameMessages::PlayerResurrectionFinished& msg) override;
|
||||
void OnFactionTriggerItemUnequipped(Entity* itemOwner, LWOOBJID itemObjId) override;
|
||||
};
|
||||
|
||||
#endif //!IMAGINATIONBACKPACK_H
|
||||
13
dScripts/EquipmentTriggers/ObyxShardPack.h
Normal file
13
dScripts/EquipmentTriggers/ObyxShardPack.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef __OBYXSHARDPACK__H__
|
||||
#define __OBYXSHARDPACK__H__
|
||||
|
||||
#include "CoilBackpackBase.h"
|
||||
|
||||
class ObyxShardPack : public CoilBackpackBase {
|
||||
public:
|
||||
ObyxShardPack() : CoilBackpackBase(skillId) {};
|
||||
private:
|
||||
static const uint32_t skillId = 1751;
|
||||
};
|
||||
|
||||
#endif //!__OBYXSHARDPACK__H__
|
||||
13
dScripts/EquipmentTriggers/RubyShardPack.h
Normal file
13
dScripts/EquipmentTriggers/RubyShardPack.h
Normal file
@@ -0,0 +1,13 @@
|
||||
#ifndef __RUBYSHARDPACK__H__
|
||||
#define __RUBYSHARDPACK__H__
|
||||
|
||||
#include "CoilBackpackBase.h"
|
||||
|
||||
class RubyShardPack : public CoilBackpackBase {
|
||||
public:
|
||||
RubyShardPack() : CoilBackpackBase(skillId) {};
|
||||
private:
|
||||
static const uint32_t skillId = 1750;
|
||||
};
|
||||
|
||||
#endif //!__RUBYSHARDPACK__H__
|
||||
27
dScripts/EquipmentTriggers/TrialFactionArmorServer.cpp
Normal file
27
dScripts/EquipmentTriggers/TrialFactionArmorServer.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include "TrialFactionArmorServer.h"
|
||||
|
||||
#include "Character.h"
|
||||
#include "ePlayerFlag.h"
|
||||
#include "DestroyableComponent.h"
|
||||
|
||||
void TrialFactionArmorServer::OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) {
|
||||
auto* character = itemOwner->GetCharacter();
|
||||
if (!character) return;
|
||||
|
||||
auto flag = character->GetPlayerFlag(ePlayerFlag::EQUPPED_TRIAL_FACTION_GEAR);
|
||||
if (!flag) {
|
||||
character->SetPlayerFlag(ePlayerFlag::EQUPPED_TRIAL_FACTION_GEAR, true);
|
||||
|
||||
// technically a TimerWithCancel but our current implementation doesnt support this.
|
||||
itemOwner->AddCallbackTimer(1.0f, [itemOwner]() {
|
||||
auto* destroyableComponent = itemOwner->GetComponent<DestroyableComponent>();
|
||||
if (!destroyableComponent) return;
|
||||
|
||||
destroyableComponent->SetHealth(destroyableComponent->GetMaxHealth());
|
||||
destroyableComponent->SetArmor(destroyableComponent->GetMaxArmor());
|
||||
destroyableComponent->SetImagination(destroyableComponent->GetMaxImagination());
|
||||
|
||||
Game::entityManager->SerializeEntity(itemOwner);
|
||||
});
|
||||
}
|
||||
}
|
||||
11
dScripts/EquipmentTriggers/TrialFactionArmorServer.h
Normal file
11
dScripts/EquipmentTriggers/TrialFactionArmorServer.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef TRIALFACTIONARMORSERVER_
|
||||
#define TRIALFACTIONARMORSERVER_
|
||||
|
||||
#include "CppScripts.h"
|
||||
|
||||
class TrialFactionArmorServer : public CppScripts::Script {
|
||||
public:
|
||||
void OnFactionTriggerItemEquipped(Entity* itemOwner, LWOOBJID itemObjId) override;
|
||||
};
|
||||
|
||||
#endif //!TRIALFACTIONARMORSERVER_
|
||||
@@ -36,14 +36,14 @@ void AgSpiderBossMessage::OnCollisionPhantom(Entity* self, Entity* target) {
|
||||
|
||||
auto box = GetBox(self);
|
||||
// knockback the target
|
||||
auto forward = target->GetRotation().GetForwardVector();
|
||||
auto forward = self->GetRotation().GetForwardVector();
|
||||
box.boxTarget = target->GetObjectID();
|
||||
GameMessages::SendPlayFXEffect(target->GetObjectID(), 1378, u"create", "pushBack");
|
||||
RenderComponent::PlayAnimation(target, "knockback-recovery");
|
||||
forward.y += 15;
|
||||
forward.x *= 100;
|
||||
forward.z *= 100;
|
||||
GameMessages::SendKnockback(target->GetObjectID(), self->GetObjectID(), self->GetObjectID(), 0, forward);
|
||||
GameMessages::SendKnockback(target->GetObjectID(), LWOOBJID_EMPTY, LWOOBJID_EMPTY, 0, forward);
|
||||
|
||||
if (box.isTouch || box.isDisplayed) return;
|
||||
box.boxSelf = self->GetObjectID();
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "eReplicaComponentType.h"
|
||||
#include "RenderComponent.h"
|
||||
#include "eGameActivity.h"
|
||||
#include "Item.h"
|
||||
#include <ranges>
|
||||
|
||||
void SGCannon::OnStartup(Entity* self) {
|
||||
LOG("OnStartup");
|
||||
@@ -81,10 +83,6 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int
|
||||
auto* player = Game::entityManager->GetEntity(self->GetVar<LWOOBJID>(PlayerIDVariable));
|
||||
if (player != nullptr) {
|
||||
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());
|
||||
|
||||
@@ -103,7 +101,6 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int
|
||||
auto* characterComponent = player->GetComponent<CharacterComponent>();
|
||||
|
||||
if (characterComponent != nullptr) {
|
||||
characterComponent->SetIsRacing(true);
|
||||
characterComponent->SetCurrentActivity(eGameActivity::SHOOTING_GALLERY);
|
||||
auto possessor = player->GetComponent<PossessorComponent>();
|
||||
if (possessor) {
|
||||
@@ -114,20 +111,12 @@ void SGCannon::OnActivityStateChangeRequest(Entity* self, LWOOBJID senderID, int
|
||||
Game::entityManager->SerializeEntity(player);
|
||||
}
|
||||
|
||||
self->SetNetworkVar<bool>(HideScoreBoardVariable, true);
|
||||
self->SetNetworkVar<bool>(ReSetSuperChargeVariable, true);
|
||||
self->SetNetworkVar<bool>(ShowLoadingUI, true);
|
||||
self->AddCallbackTimer(1.0f, [self, this]() {
|
||||
self->SetNetworkVar<bool>(HideScoreBoardVariable, 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 {
|
||||
LOG("Player not found");
|
||||
}
|
||||
@@ -245,14 +234,6 @@ void SGCannon::GameOverTimerFunc(Entity* self) {
|
||||
|
||||
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);
|
||||
|
||||
TimerToggle(self);
|
||||
@@ -261,60 +242,51 @@ void SGCannon::GameOverTimerFunc(Entity* self) {
|
||||
|
||||
void SGCannon::DoSpawnTimerFunc(Entity* self, const std::string& name) {
|
||||
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& activeSpawns = self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable);
|
||||
LOG_DEBUG("size %i, %i", activeSpawns.size(), spawnNumber);
|
||||
if (activeSpawns.size() <= spawnNumber) {
|
||||
LOG_DEBUG("Trying to spawn %i when spawns size is only %i", spawnNumber, activeSpawns.size());
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& toSpawn = activeSpawns.at(spawnNumber);
|
||||
LOG_DEBUG("toSpawn %i", toSpawn.spawnPaths.size());
|
||||
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 pathIndex = GeneralUtils::GenerateRandomNumber<size_t>(0, toSpawn.spawnPaths.size() - 1);
|
||||
const auto* path = Game::zoneManager->GetZone()->GetPath(toSpawn.spawnPaths.at(pathIndex));
|
||||
if (!path) {
|
||||
LOG_DEBUG("Path %s at index %i is null", toSpawn.spawnPaths.at(pathIndex).c_str(), pathIndex);
|
||||
if (!path || path->pathWaypoints.empty()) {
|
||||
LOG_DEBUG("Path %s at index %i or has 0 waypoints", toSpawn.spawnPaths.at(pathIndex).c_str(), pathIndex);
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG("%s", path->pathName.c_str());
|
||||
|
||||
auto info = EntityInfo{};
|
||||
info.lot = toSpawn.lot;
|
||||
info.spawnerID = self->GetObjectID();
|
||||
info.pos = path->pathWaypoints.at(0).position;
|
||||
info.pos = path->pathWaypoints[0].position;
|
||||
|
||||
info.settings = {
|
||||
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"attached_path", path->pathName),
|
||||
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);
|
||||
Game::entityManager->ConstructEntity(enemy);
|
||||
|
||||
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->SetCurrentSpeed(toSpawn.initialSpeed);
|
||||
movementAI->SetHaltDistance(0.0f);
|
||||
|
||||
std::vector<PathWaypoint> pathWaypoints = path->pathWaypoints;
|
||||
|
||||
if (GeneralUtils::GenerateRandomNumber<float_t>(0, 1) < 0.5f) {
|
||||
std::reverse(pathWaypoints.begin(), pathWaypoints.end());
|
||||
}
|
||||
|
||||
movementAI->SetPath(pathWaypoints);
|
||||
movementAI->SetPath(path->pathWaypoints);
|
||||
|
||||
enemy->AddDieCallback([this, self, enemy, name]() {
|
||||
RegisterHit(self, enemy, name);
|
||||
@@ -362,7 +334,10 @@ void SGCannon::StartGame(Entity* self) {
|
||||
|
||||
auto rewardObjects = Game::entityManager->GetEntitiesInGroup(constants.rewardModelGroup);
|
||||
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));
|
||||
@@ -400,6 +375,10 @@ void SGCannon::DoGameStartup(Entity* self) {
|
||||
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) {
|
||||
|
||||
// Add a new reward to the existing rewards
|
||||
@@ -407,6 +386,7 @@ void SGCannon::SpawnNewModel(Entity* self) {
|
||||
if (currentReward != -1) {
|
||||
auto rewards = self->GetVar<std::vector<LOT>>(RewardsVariable);
|
||||
rewards.push_back(currentReward);
|
||||
self->SetVar<std::vector<LOT>>(RewardsVariable, rewards);
|
||||
self->SetNetworkVar<int32_t>(RewardAddedVariable, currentReward);
|
||||
}
|
||||
|
||||
@@ -438,9 +418,13 @@ void SGCannon::SpawnNewModel(Entity* self) {
|
||||
std::unordered_map<LOT, int32_t> toDrop = {};
|
||||
toDrop = Loot::RollLootMatrix(player, lootMatrix);
|
||||
|
||||
for (auto drop : toDrop) {
|
||||
rewardModel->OnFireEventServerSide(self, ModelToBuildEvent, drop.first);
|
||||
self->SetVar<LOT>(CurrentRewardVariable, drop.first);
|
||||
for (const auto [lot, count] : toDrop) {
|
||||
GameMessages::SetModelToBuild modelToBuild{};
|
||||
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);
|
||||
|
||||
if (currentWave > 0) {
|
||||
auto totalWaveScore = 0;
|
||||
auto totalWaveScore = totalScore;
|
||||
auto playerScores = self->GetVar<std::vector<int32_t>>(PlayerScoresVariable);
|
||||
|
||||
for (const auto& waveScore : playerScores) {
|
||||
totalWaveScore += waveScore;
|
||||
totalWaveScore -= waveScore;
|
||||
}
|
||||
|
||||
if (currentWave >= playerScores.size()) {
|
||||
@@ -526,6 +510,7 @@ void SGCannon::RecordPlayerScore(Entity* self) {
|
||||
} else {
|
||||
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) {
|
||||
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<uint32_t>(CurrentSuperChargedTimeVariable, time);
|
||||
self->SetNetworkVar<uint32_t>(ChargeCountingVariable, time);
|
||||
|
||||
ActivityTimerStop(self, SuperChargeTimer);
|
||||
}
|
||||
|
||||
@@ -568,14 +552,17 @@ void SGCannon::StopGame(Entity* self, bool cancel) {
|
||||
|
||||
// The player won, store all the score and send rewards
|
||||
if (!cancel) {
|
||||
int32_t percentage = 0.0f;
|
||||
auto misses = self->GetVar<uint32_t>(MissesVariable);
|
||||
auto fired = self->GetVar<uint32_t>(ShotsFiredVariable);
|
||||
float percentage = 0.0f;
|
||||
float misses = self->GetVar<uint32_t>(MissesVariable);
|
||||
float fired = self->GetVar<uint32_t>(ShotsFiredVariable);
|
||||
|
||||
if (fired > 0) {
|
||||
if (fired > 0.0f) {
|
||||
percentage = misses / fired;
|
||||
}
|
||||
|
||||
percentage = 1.0f - percentage;
|
||||
percentage = std::max(percentage, 0.0f);
|
||||
|
||||
auto* missionComponent = player->GetComponent<MissionComponent>();
|
||||
|
||||
if (missionComponent != nullptr) {
|
||||
@@ -596,13 +583,27 @@ void SGCannon::StopGame(Entity* self, bool cancel) {
|
||||
auto* inventory = player->GetComponent<InventoryComponent>();
|
||||
if (inventory != nullptr) {
|
||||
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",
|
||||
GeneralUtils::to_u16string(self->GetVar<int32_t>(TotalScoreVariable)) + u"_0_0_0_0_0_0"
|
||||
);
|
||||
const auto& waveScores = self->GetVar<std::vector<int32_t>>(PlayerScoresVariable);
|
||||
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());
|
||||
@@ -617,10 +618,42 @@ void SGCannon::StopGame(Entity* self, bool cancel) {
|
||||
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) {
|
||||
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");
|
||||
|
||||
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);
|
||||
|
||||
ActivityTimerStart(self, timerName, respawnTime, respawnTime);
|
||||
@@ -637,6 +670,7 @@ void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& time
|
||||
} else {
|
||||
if (!self->GetVar<bool>(SuperChargeActiveVariable)) {
|
||||
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);
|
||||
@@ -646,10 +680,6 @@ void SGCannon::RegisterHit(Entity* self, Entity* target, const std::string& time
|
||||
|
||||
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) {
|
||||
StartChargedCannon(self);
|
||||
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;
|
||||
|
||||
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) {
|
||||
@@ -745,41 +809,34 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) {
|
||||
|
||||
auto* selfInventoryComponent = self->GetComponent<InventoryComponent>();
|
||||
|
||||
if (inventoryComponent == nullptr) {
|
||||
LOG("Inventory component not found");
|
||||
// This is a gm in the original script
|
||||
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;
|
||||
}
|
||||
|
||||
if (enable) {
|
||||
LOG("Player is activating super charge");
|
||||
selfInventoryComponent->UpdateSlot("greeble_r", { ObjectIDManager::GenerateRandomObjectID(), 6505, 1, 0 });
|
||||
selfInventoryComponent->UpdateSlot("greeble_l", { ObjectIDManager::GenerateRandomObjectID(), 6506, 1, 0 });
|
||||
selfInventoryComponent->EquipItem(meItem1);
|
||||
selfInventoryComponent->EquipItem(meItem2);
|
||||
|
||||
// TODO: Equip items
|
||||
skillID = constants.cannonSuperChargeSkill;
|
||||
cooldown = 400;
|
||||
} else {
|
||||
selfInventoryComponent->UpdateSlot("greeble_r", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 });
|
||||
selfInventoryComponent->UpdateSlot("greeble_l", { ObjectIDManager::GenerateRandomObjectID(), 0, 0, 0 });
|
||||
selfInventoryComponent->UnEquipItem(meItem1);
|
||||
selfInventoryComponent->UnEquipItem(meItem2);
|
||||
|
||||
self->SetNetworkVar<float>(u"SuperChargeBar", 0);
|
||||
|
||||
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;
|
||||
self->SetVar<uint32_t>(NumberOfChargesVariable, 0);
|
||||
}
|
||||
@@ -794,10 +851,10 @@ void SGCannon::ToggleSuperCharge(Entity* self, bool enable) {
|
||||
|
||||
DynamicShootingGalleryParams properties = shootingGalleryComponent->GetDynamicParams();
|
||||
|
||||
properties.cannonFOV = 58.6f;
|
||||
properties.cannonVelocity = 129.0;
|
||||
properties.cannonFOV = constants.cannonFOV;
|
||||
properties.cannonVelocity = constants.cannonVelocity;
|
||||
properties.cannonRefireRate = cooldown;
|
||||
properties.cannonMinDistance = 30;
|
||||
properties.cannonMinDistance = constants.cannonMinDistance;
|
||||
properties.cannonTimeout = -1;
|
||||
|
||||
shootingGalleryComponent->SetDynamicParams(properties);
|
||||
@@ -829,22 +886,38 @@ std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() {
|
||||
1.0, false, true
|
||||
},
|
||||
|
||||
// Sub 1
|
||||
// Sub 1 but for dlu
|
||||
{
|
||||
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
|
||||
{
|
||||
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 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
|
||||
{
|
||||
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
|
||||
//{
|
||||
// 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" },
|
||||
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
|
||||
},
|
||||
|
||||
@@ -963,11 +1044,19 @@ std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() {
|
||||
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
|
||||
{
|
||||
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,
|
||||
3.0, 1000, false, 0.0, 1.0,
|
||||
1.0, true, true
|
||||
},
|
||||
|
||||
@@ -987,14 +1076,22 @@ std::vector<std::vector<SGEnemy>> SGCannon::GetWaves() {
|
||||
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" },
|
||||
2565, 10.0, 15.0, true, 10.0, 15.0,
|
||||
2.0, 10000, false, 0.0, 1.0,
|
||||
1.0, true, true
|
||||
7.0, 10000, false, 0.0, 7.0,
|
||||
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
|
||||
{
|
||||
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<uint32_t>(u"m_curStreak", 0);
|
||||
self->SetNetworkVar<float>(u"SuperChargeBar", 0);
|
||||
self->SetVar<uint32_t>(u"LastSuperTotal", 0);
|
||||
self->SetNetworkVar<float>(u"SuperChargeBar", 0.0f);
|
||||
self->SetNetworkVar<bool>(u"ShowStreak", 0);
|
||||
self->SetNetworkVar<bool>(u"UnMarkAll", true);
|
||||
self->SetVar<std::vector<LWOOBJID>>(u"LastHitTarget", {});
|
||||
|
||||
const_cast<std::vector<SGEnemy>&>(self->GetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable)).clear();
|
||||
self->SetVar<std::vector<SGEnemy>>(ActiveSpawnsVariable, {});
|
||||
@@ -1056,40 +1150,42 @@ void SGCannon::ResetVars(Entity* self) {
|
||||
|
||||
SGConstants SGCannon::GetConstants() {
|
||||
return {
|
||||
Vector3 { -908.542480, 229.773178, -908.542480 },
|
||||
Quaternion { 0.91913521289825, 0, 0.39394217729568, 0 },
|
||||
1864,
|
||||
34,
|
||||
1822,
|
||||
Vector3 { 6.652, -2, 1.5 },
|
||||
157,
|
||||
129.0,
|
||||
30.0,
|
||||
800.0,
|
||||
Vector3 { 0, 4.3, 9 },
|
||||
6297,
|
||||
1822,
|
||||
249,
|
||||
228,
|
||||
-1,
|
||||
58.6,
|
||||
true,
|
||||
2,
|
||||
10,
|
||||
25000,
|
||||
"QBRewardGroup",
|
||||
1864,
|
||||
50000,
|
||||
157,
|
||||
100000,
|
||||
187,
|
||||
200000,
|
||||
188,
|
||||
400000,
|
||||
189,
|
||||
800000,
|
||||
190,
|
||||
4.0,
|
||||
7.0
|
||||
.playerStartPosition = Vector3 { -908.542480, 229.773178, -908.542480 },
|
||||
.playerStartRotation = Quaternion { 0.91913521289825, 0, 0.39394217729568, 0 },
|
||||
.cannonLot = 1864,
|
||||
.impactSkillID = 34,
|
||||
.projectileLot = 1822,
|
||||
.playerOffset = Vector3 { 6.652, -2, 1.5 },
|
||||
.rewardModelMatrix = 157,
|
||||
.cannonVelocity = 129.0,
|
||||
.cannonMinDistance = 30.0,
|
||||
.cannonRefireRate = 800.0,
|
||||
.cannonBarrelOffset = Vector3 { 0, 4.3, 9 },
|
||||
.cannonSuperchargedProjectileLot = 6297,
|
||||
.cannonProjectileLot = 1822,
|
||||
.cannonSuperChargeSkill = 249,
|
||||
.cannonSkill = 228,
|
||||
.cannonTimeout = -1,
|
||||
.cannonFOV = 58.6,
|
||||
.useLeaderboards = true,
|
||||
.streakModifier = 2,
|
||||
.chargedTime = 10,
|
||||
.chargedPoints = 25000,
|
||||
.rewardModelGroup = "QBRewardGroup",
|
||||
.activityID = 1864,
|
||||
.scoreRewards = {
|
||||
{"Score_Reward_1", 50000},
|
||||
{"Score_Reward_2", 100000},
|
||||
{"Score_Reward_3", 200000},
|
||||
{"Score_Reward_4", 400000},
|
||||
{"Score_Reward_5", 800000},
|
||||
},
|
||||
.scoreLootMatrix1 = 157,
|
||||
.scoreLootMatrix2 = 187,
|
||||
.scoreLootMatrix3 = 188,
|
||||
.scoreLootMatrix4 = 189,
|
||||
.scoreLootMatrix5 = 190,
|
||||
.firstWaveStartTime = 4.0,
|
||||
.inBetweenWavePause = 7.0
|
||||
};
|
||||
}
|
||||
|
||||
@@ -44,15 +44,11 @@ struct SGConstants {
|
||||
uint32_t chargedPoints;
|
||||
std::string rewardModelGroup;
|
||||
uint32_t activityID;
|
||||
uint32_t scoreReward1;
|
||||
std::map<std::string, uint32_t> scoreRewards;
|
||||
uint32_t scoreLootMatrix1;
|
||||
uint32_t scoreReward2;
|
||||
uint32_t scoreLootMatrix2;
|
||||
uint32_t scoreReward3;
|
||||
uint32_t scoreLootMatrix3;
|
||||
uint32_t scoreReward4;
|
||||
uint32_t scoreLootMatrix4;
|
||||
uint32_t scoreReward5;
|
||||
uint32_t scoreLootMatrix5;
|
||||
float_t firstWaveStartTime;
|
||||
float_t inBetweenWavePause;
|
||||
@@ -68,6 +64,8 @@ public:
|
||||
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 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 SpawnWaveTimerFunc(Entity* self);
|
||||
void EndWaveTimerFunc(Entity* self);
|
||||
@@ -142,6 +140,7 @@ private:
|
||||
std::u16string CannonBallSkillIDVariable = u"cbskill";
|
||||
std::u16string HideSuperChargeVariable = u"HideSuper";
|
||||
std::u16string AudioFinalWaveDoneVariable = u"Audio_Final_Wave_Done";
|
||||
std::u16string ModelPercentVariable = u"modelPercent";
|
||||
|
||||
std::string SpawnWaveTimer = "SpawnWave";
|
||||
std::string EndWaveTimer = "EndWave";
|
||||
|
||||
@@ -13,6 +13,18 @@ foreach(file ${DSCRIPTS_SOURCES_AI_RACING_TRACK_NS})
|
||||
set(DSCRIPTS_SOURCES_AI_RACING ${DSCRIPTS_SOURCES_AI_RACING} "TRACK_NS/${file}")
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(TRACK_GF)
|
||||
|
||||
foreach(file ${DSCRIPTS_SOURCES_AI_RACING_TRACK_GF})
|
||||
set(DSCRIPTS_SOURCES_AI_RACING ${DSCRIPTS_SOURCES_AI_RACING} "TRACK_GF/${file}")
|
||||
endforeach()
|
||||
|
||||
add_subdirectory(TRACK_FV)
|
||||
|
||||
foreach(file ${DSCRIPTS_SOURCES_AI_RACING_TRACK_FV})
|
||||
set(DSCRIPTS_SOURCES_AI_RACING ${DSCRIPTS_SOURCES_AI_RACING} "TRACK_FV/${file}")
|
||||
endforeach()
|
||||
|
||||
add_library(dScriptsAiRacing OBJECT ${DSCRIPTS_SOURCES_AI_RACING})
|
||||
target_include_directories(dScriptsAiRacing PUBLIC "." "OBJECTS" "TRACK_NS")
|
||||
target_include_directories(dScriptsAiRacing PUBLIC "." "OBJECTS" "TRACK_NS" "TRACK_GF" "TRACK_FV")
|
||||
target_precompile_headers(dScriptsAiRacing REUSE_FROM dScriptsBase)
|
||||
|
||||
@@ -7,4 +7,5 @@ set(DSCRIPTS_SOURCES_AI_RACING_OBJECTS
|
||||
"FvRacePillarDServer.cpp"
|
||||
"FvRaceSmashEggImagineServer.cpp"
|
||||
"RaceSmashServer.cpp"
|
||||
"VehicleDeathTriggerWaterServer.cpp"
|
||||
PARENT_SCOPE)
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#include "VehicleDeathTriggerWaterServer.h"
|
||||
|
||||
#include "PossessorComponent.h"
|
||||
#include "RacingControlComponent.h"
|
||||
|
||||
void VehicleDeathTriggerWaterServer::OnCollisionPhantom(Entity* self, Entity* target) {
|
||||
if (target->IsPlayer() && !target->GetIsDead()) {
|
||||
const std::vector<Entity*> racingControllers = Game::entityManager->GetEntitiesByComponent(RacingControlComponent::ComponentType);
|
||||
for (auto* const racingController : racingControllers) {
|
||||
auto* racingControlComponent = racingController->GetComponent<RacingControlComponent>();
|
||||
if (racingControlComponent) {
|
||||
racingControlComponent->OnRequestDie(target, u"death_water");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
dScripts/ai/RACING/OBJECTS/VehicleDeathTriggerWaterServer.h
Normal file
11
dScripts/ai/RACING/OBJECTS/VehicleDeathTriggerWaterServer.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef VEHICLEDEATHTRIGGERWATERSERVER_H
|
||||
#define VEHICLEDEATHTRIGGERWATERSERVER_H
|
||||
|
||||
#include "CppScripts.h"
|
||||
|
||||
class VehicleDeathTriggerWaterServer : public CppScripts::Script {
|
||||
public:
|
||||
void OnCollisionPhantom(Entity* self, Entity* target) override;
|
||||
};
|
||||
|
||||
#endif //!VEHICLEDEATHTRIGGERWATERSERVER_H
|
||||
3
dScripts/ai/RACING/TRACK_FV/CMakeLists.txt
Normal file
3
dScripts/ai/RACING/TRACK_FV/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
set(DSCRIPTS_SOURCES_AI_RACING_TRACK_FV
|
||||
"FvRaceServer.cpp"
|
||||
PARENT_SCOPE)
|
||||
55
dScripts/ai/RACING/TRACK_FV/FvRaceServer.cpp
Normal file
55
dScripts/ai/RACING/TRACK_FV/FvRaceServer.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "FvRaceServer.h"
|
||||
|
||||
#include "RacingControlComponent.h"
|
||||
#include "Entity.h"
|
||||
|
||||
using std::unique_ptr;
|
||||
using std::make_unique;
|
||||
|
||||
void FvRaceServer::OnStartup(Entity* self) {
|
||||
GameMessages::ConfigureRacingControl config;
|
||||
auto& raceSet = config.racingSettings;
|
||||
|
||||
raceSet.push_back(make_unique<LDFData<std::u16string>>(u"GameType", u"Racing"));
|
||||
raceSet.push_back(make_unique<LDFData<std::u16string>>(u"GameState", u"Starting"));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Number_Of_PlayersPerTeam", 6));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Minimum_Players_to_Start", 2));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Minimum_Players_for_Group_Achievements", 2));
|
||||
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Car_Object", 7703));
|
||||
raceSet.push_back(make_unique<LDFData<std::u16string>>(u"Race_PathName", u"MainPath"));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Current_Lap", 1));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Number_of_Laps", 3));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"activityID", 54));
|
||||
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Place_1", 100));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Place_2", 90));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Place_3", 80));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Place_4", 70));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Place_5", 60));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Place_6", 50));
|
||||
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Num_of_Players_1", 15));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Num_of_Players_2", 25));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Num_of_Players_3", 50));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Num_of_Players_4", 85));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Num_of_Players_5", 90));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Num_of_Players_6", 100));
|
||||
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Number_of_Spawn_Groups", 1));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Red_Spawners", 4847));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Blue_Spawners", 4848));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Blue_Flag", 4850));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Red_Flag", 4851));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Red_Point", 4846));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Blue_Point", 4845));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Red_Mark", 4844));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Blue_Mark", 4843));
|
||||
|
||||
const std::vector<Entity*> racingControllers = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL);
|
||||
for (auto* const racingController : racingControllers) {
|
||||
auto* racingComponent = racingController->GetComponent<RacingControlComponent>();
|
||||
if (racingComponent) racingComponent->MsgConfigureRacingControl(config);
|
||||
}
|
||||
}
|
||||
|
||||
11
dScripts/ai/RACING/TRACK_FV/FvRaceServer.h
Normal file
11
dScripts/ai/RACING/TRACK_FV/FvRaceServer.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef FVRACESERVER_H
|
||||
#define FVRACESERVER_H
|
||||
|
||||
#include "RaceImaginationServer.h"
|
||||
|
||||
class FvRaceServer : public RaceImaginationServer {
|
||||
public:
|
||||
void OnStartup(Entity* self) override;
|
||||
};
|
||||
|
||||
#endif //!FVRACESERVER_H
|
||||
3
dScripts/ai/RACING/TRACK_GF/CMakeLists.txt
Normal file
3
dScripts/ai/RACING/TRACK_GF/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
set(DSCRIPTS_SOURCES_AI_RACING_TRACK_GF
|
||||
"GfRaceServer.cpp"
|
||||
PARENT_SCOPE)
|
||||
55
dScripts/ai/RACING/TRACK_GF/GfRaceServer.cpp
Normal file
55
dScripts/ai/RACING/TRACK_GF/GfRaceServer.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#include "GfRaceServer.h"
|
||||
|
||||
#include "RacingControlComponent.h"
|
||||
#include "Entity.h"
|
||||
|
||||
using std::unique_ptr;
|
||||
using std::make_unique;
|
||||
|
||||
void GfRaceServer::OnStartup(Entity* self) {
|
||||
GameMessages::ConfigureRacingControl config;
|
||||
auto& raceSet = config.racingSettings;
|
||||
|
||||
raceSet.push_back(make_unique<LDFData<std::u16string>>(u"GameType", u"Racing"));
|
||||
raceSet.push_back(make_unique<LDFData<std::u16string>>(u"GameState", u"Starting"));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Number_Of_PlayersPerTeam", 6));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Minimum_Players_to_Start", 2));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Minimum_Players_for_Group_Achievements", 2));
|
||||
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Car_Object", 7703));
|
||||
raceSet.push_back(make_unique<LDFData<std::u16string>>(u"Race_PathName", u"MainPath"));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Current_Lap", 1));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Number_of_Laps", 3));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"activityID", 39));
|
||||
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Place_1", 100));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Place_2", 90));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Place_3", 80));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Place_4", 70));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Place_5", 60));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Place_6", 50));
|
||||
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Num_of_Players_1", 15));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Num_of_Players_2", 25));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Num_of_Players_3", 50));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Num_of_Players_4", 85));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Num_of_Players_5", 90));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Num_of_Players_6", 100));
|
||||
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Number_of_Spawn_Groups", 1));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Red_Spawners", 4847));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Blue_Spawners", 4848));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Blue_Flag", 4850));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Red_Flag", 4851));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Red_Point", 4846));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Blue_Point", 4845));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Red_Mark", 4844));
|
||||
raceSet.push_back(make_unique<LDFData<int32_t>>(u"Blue_Mark", 4843));
|
||||
|
||||
const std::vector<Entity*> racingControllers = Game::entityManager->GetEntitiesByComponent(eReplicaComponentType::RACING_CONTROL);
|
||||
for (auto* const racingController : racingControllers) {
|
||||
auto* racingComponent = racingController->GetComponent<RacingControlComponent>();
|
||||
if (racingComponent) racingComponent->MsgConfigureRacingControl(config);
|
||||
}
|
||||
}
|
||||
|
||||
11
dScripts/ai/RACING/TRACK_GF/GfRaceServer.h
Normal file
11
dScripts/ai/RACING/TRACK_GF/GfRaceServer.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef GFRACESERVER_H
|
||||
#define GFRACESERVER_H
|
||||
|
||||
#include "RaceImaginationServer.h"
|
||||
|
||||
class GfRaceServer : public RaceImaginationServer {
|
||||
public:
|
||||
void OnStartup(Entity* self) override;
|
||||
};
|
||||
|
||||
#endif //!GFRACESERVER_H
|
||||
@@ -202,11 +202,13 @@ int main(int argc, char** argv) {
|
||||
//Find out the master's IP:
|
||||
std::string masterIP = "localhost";
|
||||
uint32_t masterPort = 1000;
|
||||
std::string masterPassword;
|
||||
auto masterInfo = Database::Get()->GetMasterInfo();
|
||||
|
||||
if (masterInfo) {
|
||||
masterIP = masterInfo->ip;
|
||||
masterPort = masterInfo->port;
|
||||
masterPassword = masterInfo->password;
|
||||
}
|
||||
|
||||
UserManager::Instance()->Initialize();
|
||||
@@ -214,7 +216,7 @@ int main(int argc, char** argv) {
|
||||
const bool dontGenerateDCF = GeneralUtils::TryParse<bool>(Game::config->GetValue("dont_generate_dcf")).value_or(false);
|
||||
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", dontGenerateDCF);
|
||||
|
||||
Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, &Game::lastSignal, zoneID);
|
||||
Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, &Game::lastSignal, masterPassword, zoneID);
|
||||
|
||||
//Connect to the chat server:
|
||||
uint32_t chatPort = 1501;
|
||||
@@ -223,7 +225,7 @@ int main(int argc, char** argv) {
|
||||
auto chatSock = SocketDescriptor(static_cast<uint16_t>(ourPort + 2), 0);
|
||||
Game::chatServer = RakNetworkFactory::GetRakPeerInterface();
|
||||
Game::chatServer->Startup(1, 30, &chatSock, 1);
|
||||
Game::chatServer->Connect(masterIP.c_str(), chatPort, "3.25 ND1", 8);
|
||||
Game::chatServer->Connect(masterIP.c_str(), chatPort, NET_PASSWORD_EXTERNAL, strnlen(NET_PASSWORD_EXTERNAL, sizeof(NET_PASSWORD_EXTERNAL)));
|
||||
|
||||
//Set up other things:
|
||||
Game::randomEngine = std::mt19937(time(0));
|
||||
@@ -371,7 +373,7 @@ int main(int argc, char** argv) {
|
||||
if (framesSinceChatDisconnect >= chatReconnectionTime) {
|
||||
framesSinceChatDisconnect = 0;
|
||||
|
||||
Game::chatServer->Connect(masterIP.c_str(), chatPort, "3.25 ND1", 8);
|
||||
Game::chatServer->Connect(masterIP.c_str(), chatPort, NET_PASSWORD_EXTERNAL, strnlen(NET_PASSWORD_EXTERNAL, sizeof(NET_PASSWORD_EXTERNAL)));
|
||||
}
|
||||
} else framesSinceChatDisconnect = 0;
|
||||
|
||||
|
||||
1
migrations/dlu/mysql/18_master_password.sql
Normal file
1
migrations/dlu/mysql/18_master_password.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE servers ADD COLUMN master_password TEXT NOT NULL DEFAULT ('3.25 DARKFLAME1');
|
||||
1
migrations/dlu/sqlite/1_master_password.sql
Normal file
1
migrations/dlu/sqlite/1_master_password.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE servers ADD COLUMN master_password TEXT NOT NULL DEFAULT ('3.25 DARKFLAME1');
|
||||
@@ -7,15 +7,7 @@ master_server_port=2000
|
||||
# The port number to start world servers on. Will be incremented for each world
|
||||
world_port_start=3000
|
||||
|
||||
# Use sudo when launching the auth server.
|
||||
# Required by default if on Linux as auth runs on port 1001
|
||||
use_sudo_auth=1
|
||||
|
||||
# Use sudo when launching the chat server
|
||||
use_sudo_chat=0
|
||||
|
||||
# Use sudo when launching world servers
|
||||
use_sudo_world=0
|
||||
|
||||
# 0 or 1, should autostart auth, chat, and char servers
|
||||
prestart_servers=1
|
||||
|
||||
master_password=3.25DARKFLAME1
|
||||
|
||||
1
thirdparty/cpp-httplib
vendored
1
thirdparty/cpp-httplib
vendored
Submodule thirdparty/cpp-httplib deleted from 824e7682e4
Reference in New Issue
Block a user