mirror of
https://github.com/DarkflameUniverse/DarkflameServer
synced 2024-08-30 18:43:58 +00:00
Merge remote-tracking branch 'origin/main' into dCinema
This commit is contained in:
commit
a09bbdba32
39
README.md
39
README.md
@ -224,6 +224,44 @@ sudo setcap 'cap_net_bind_service=+ep' AuthServer
|
|||||||
```
|
```
|
||||||
and then go to `build/masterconfig.ini` and change `use_sudo_auth` to 0.
|
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.
|
||||||
|
_Note: You could use screen or tmux instead for virtual terminals_
|
||||||
|
To run the server non-interactively, we can use a systemctl service by copying the following file:
|
||||||
|
```shell
|
||||||
|
cp ./systemd.example /etc/systemd/system/darkflame.service
|
||||||
|
```
|
||||||
|
|
||||||
|
Make sure to edit the file in `/etc/systemd/system/darkflame.service` and change the:
|
||||||
|
- `User` and `Group` to the user that runs the darkflame server.
|
||||||
|
- `ExecPath` to the full file path of the server executable.
|
||||||
|
|
||||||
|
To register, enable and start the service use the following commands:
|
||||||
|
|
||||||
|
- Reload the systemd manager configuration to make it aware of the new service file:
|
||||||
|
```shell
|
||||||
|
systemctl daemon-reload
|
||||||
|
```
|
||||||
|
- Start the service:
|
||||||
|
```shell
|
||||||
|
systemctl start darkflame.service
|
||||||
|
```
|
||||||
|
- Enable OR disable the service to start on boot using:
|
||||||
|
```shell
|
||||||
|
systemctl enable darkflame.service
|
||||||
|
systemctl disable darkflame.service
|
||||||
|
```
|
||||||
|
- Verify that the service is running without errors:
|
||||||
|
```shell
|
||||||
|
systemctl status darkflame.service
|
||||||
|
```
|
||||||
|
- You can also restart, stop, or check the logs of the service using journalctl
|
||||||
|
```shell
|
||||||
|
systemctl restart darkflame.service
|
||||||
|
systemctl stop darkflame.service
|
||||||
|
journalctl -xeu darkflame.service
|
||||||
|
```
|
||||||
|
|
||||||
### First admin user
|
### First admin user
|
||||||
Run `MasterServer -a` to get prompted to create an admin account. This method is only intended for the system administrator as a means to get started, do NOT use this method to create accounts for other users!
|
Run `MasterServer -a` to get prompted to create an admin account. This method is only intended for the system administrator as a means to get started, do NOT use this method to create accounts for other users!
|
||||||
|
|
||||||
@ -285,6 +323,7 @@ Below are known good SHA256 checksums of the client:
|
|||||||
* `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed)
|
* `0d862f71eedcadc4494c4358261669721b40b2131101cbd6ef476c5a6ec6775b` (unpacked client, includes extra locales, rar compressed)
|
||||||
|
|
||||||
If the returned hash matches one of the lines above then you can continue with setting up the server. If you are using a fully downloaded and complete client from live, then it will work, but the hash above may not match. Otherwise you must obtain a full install of LEGO® Universe 1.10.64.
|
If the returned hash matches one of the lines above then you can continue with setting up the server. If you are using a fully downloaded and complete client from live, then it will work, but the hash above may not match. Otherwise you must obtain a full install of LEGO® Universe 1.10.64.
|
||||||
|
You must also make absolutely sure your LEGO Universe client is not in a Windows OneDrive. DLU is not and will not support a client being stored in a OneDrive, so ensure you have moved the client outside of that location.
|
||||||
|
|
||||||
### Darkflame Universe Client
|
### Darkflame Universe Client
|
||||||
Darkflame Universe clients identify themselves using a higher version number than the regular live clients out there.
|
Darkflame Universe clients identify themselves using a higher version number than the regular live clients out there.
|
||||||
|
@ -144,7 +144,7 @@ std::vector<std::pair<uint8_t, uint8_t>> dChatFilter::IsSentenceOkay(const std::
|
|||||||
listOfBadSegments.emplace_back(position, originalSegment.length());
|
listOfBadSegments.emplace_back(position, originalSegment.length());
|
||||||
}
|
}
|
||||||
|
|
||||||
position += segment.length() + 1;
|
position += originalSegment.length() + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return listOfBadSegments;
|
return listOfBadSegments;
|
||||||
|
@ -24,7 +24,6 @@ void SortTable(LootTableEntries& table) {
|
|||||||
lootToInsert = oldItrInner;
|
lootToInsert = oldItrInner;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Game::logger->LogDebug("CDLootTableTable", "highest rarity %i item id %i", highestLootRarity, lootToInsert->itemid);
|
|
||||||
std::swap(*oldItrOuter, *lootToInsert);
|
std::swap(*oldItrOuter, *lootToInsert);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1037,7 +1037,7 @@ void GameMessages::SendSetNetworkScriptVar(Entity* entity, const SystemAddress&
|
|||||||
}
|
}
|
||||||
|
|
||||||
void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, LOT item, int currency, NiPoint3 spawnPos, int count) {
|
void GameMessages::SendDropClientLoot(Entity* entity, const LWOOBJID& sourceID, LOT item, int currency, NiPoint3 spawnPos, int count) {
|
||||||
if (Game::config->GetValue("disable_drops") == "1") {
|
if (Game::config->GetValue("disable_drops") == "1" || !entity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2531,15 +2531,9 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent
|
|||||||
inStream->Read(sd0Size);
|
inStream->Read(sd0Size);
|
||||||
std::shared_ptr<char[]> sd0Data(new char[sd0Size]);
|
std::shared_ptr<char[]> sd0Data(new char[sd0Size]);
|
||||||
|
|
||||||
if (sd0Data == nullptr) {
|
if (sd0Data == nullptr) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < sd0Size; ++i) {
|
inStream->ReadAlignedBytes(reinterpret_cast<unsigned char*>(sd0Data.get()), sd0Size);
|
||||||
uint8_t c;
|
|
||||||
inStream->Read(c);
|
|
||||||
sd0Data[i] = c;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t timeTaken;
|
uint32_t timeTaken;
|
||||||
inStream->Read(timeTaken);
|
inStream->Read(timeTaken);
|
||||||
@ -2573,165 +2567,156 @@ void GameMessages::HandleBBBSaveRequest(RakNet::BitStream* inStream, Entity* ent
|
|||||||
|
|
||||||
//We runs this in async because the http library here is blocking, meaning it'll halt the thread.
|
//We runs this in async because the http library here is blocking, meaning it'll halt the thread.
|
||||||
//But we don't want the server to go unresponsive, because then the client would disconnect.
|
//But we don't want the server to go unresponsive, because then the client would disconnect.
|
||||||
auto returnVal = std::async(std::launch::async, [&]() {
|
|
||||||
|
|
||||||
//We need to get a new ID for our model first:
|
//We need to get a new ID for our model first:
|
||||||
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t newID) {
|
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t newID) {
|
||||||
LWOOBJID newIDL = newID;
|
LWOOBJID newIDL = newID;
|
||||||
GeneralUtils::SetBit(newIDL, eObjectBits::CHARACTER);
|
GeneralUtils::SetBit(newIDL, eObjectBits::CHARACTER);
|
||||||
GeneralUtils::SetBit(newIDL, eObjectBits::PERSISTENT);
|
GeneralUtils::SetBit(newIDL, eObjectBits::PERSISTENT);
|
||||||
|
|
||||||
ObjectIDManager::Instance()->RequestPersistentID([=](uint32_t blueprintIDSmall) {
|
uint32_t blueprintIDSmall = ObjectIDManager::Instance()->GenerateRandomObjectID();
|
||||||
blueprintIDSmall = ObjectIDManager::Instance()->GenerateRandomObjectID();
|
LWOOBJID blueprintID = blueprintIDSmall;
|
||||||
LWOOBJID blueprintID = blueprintIDSmall;
|
GeneralUtils::SetBit(blueprintID, eObjectBits::CHARACTER);
|
||||||
GeneralUtils::SetBit(blueprintID, eObjectBits::CHARACTER);
|
GeneralUtils::SetBit(blueprintID, eObjectBits::PERSISTENT);
|
||||||
GeneralUtils::SetBit(blueprintID, eObjectBits::PERSISTENT);
|
|
||||||
|
|
||||||
//We need to get the propertyID: (stolen from Wincent's propertyManagementComp)
|
//We need to get the propertyID: (stolen from Wincent's propertyManagementComp)
|
||||||
const auto& worldId = Game::zoneManager->GetZone()->GetZoneID();
|
const auto& worldId = Game::zoneManager->GetZone()->GetZoneID();
|
||||||
|
|
||||||
const auto zoneId = worldId.GetMapID();
|
const auto zoneId = worldId.GetMapID();
|
||||||
const auto cloneId = worldId.GetCloneID();
|
const auto cloneId = worldId.GetCloneID();
|
||||||
|
|
||||||
auto query = CDClientDatabase::CreatePreppedStmt(
|
auto query = CDClientDatabase::CreatePreppedStmt(
|
||||||
"SELECT id FROM PropertyTemplate WHERE mapID = ?;");
|
"SELECT id FROM PropertyTemplate WHERE mapID = ?;");
|
||||||
query.bind(1, (int)zoneId);
|
query.bind(1, (int)zoneId);
|
||||||
|
|
||||||
auto result = query.execQuery();
|
auto result = query.execQuery();
|
||||||
|
|
||||||
if (result.eof() || result.fieldIsNull(0)) return;
|
if (result.eof() || result.fieldIsNull(0)) return;
|
||||||
|
|
||||||
int templateId = result.getIntField(0);
|
int templateId = result.getIntField(0);
|
||||||
|
|
||||||
result.finalize();
|
auto* propertyLookup = Database::CreatePreppedStmt("SELECT * FROM properties WHERE template_id = ? AND clone_id = ?;");
|
||||||
|
|
||||||
auto* propertyLookup = Database::CreatePreppedStmt("SELECT * FROM properties WHERE template_id = ? AND clone_id = ?;");
|
propertyLookup->setInt(1, templateId);
|
||||||
|
propertyLookup->setInt64(2, cloneId);
|
||||||
|
|
||||||
propertyLookup->setInt(1, templateId);
|
auto* propertyEntry = propertyLookup->executeQuery();
|
||||||
propertyLookup->setInt64(2, cloneId);
|
uint64_t propertyId = 0;
|
||||||
|
|
||||||
auto* propertyEntry = propertyLookup->executeQuery();
|
if (propertyEntry->next()) {
|
||||||
uint64_t propertyId = 0;
|
propertyId = propertyEntry->getUInt64(1);
|
||||||
|
}
|
||||||
|
|
||||||
if (propertyEntry->next()) {
|
delete propertyEntry;
|
||||||
propertyId = propertyEntry->getUInt64(1);
|
delete propertyLookup;
|
||||||
}
|
|
||||||
|
|
||||||
delete propertyEntry;
|
//Insert into ugc:
|
||||||
delete propertyLookup;
|
auto ugcs = Database::CreatePreppedStmt("INSERT INTO `ugc`(`id`, `account_id`, `character_id`, `is_optimized`, `lxfml`, `bake_ao`, `filename`) VALUES (?,?,?,?,?,?,?)");
|
||||||
|
ugcs->setUInt(1, blueprintIDSmall);
|
||||||
|
ugcs->setInt(2, entity->GetParentUser()->GetAccountID());
|
||||||
|
ugcs->setInt(3, entity->GetCharacter()->GetID());
|
||||||
|
ugcs->setInt(4, 0);
|
||||||
|
|
||||||
//Insert into ugc:
|
//whacky stream biz
|
||||||
auto ugcs = Database::CreatePreppedStmt("INSERT INTO `ugc`(`id`, `account_id`, `character_id`, `is_optimized`, `lxfml`, `bake_ao`, `filename`) VALUES (?,?,?,?,?,?,?)");
|
std::string s(sd0Data.get(), sd0Size);
|
||||||
ugcs->setUInt(1, blueprintIDSmall);
|
std::istringstream iss(s);
|
||||||
ugcs->setInt(2, entity->GetParentUser()->GetAccountID());
|
|
||||||
ugcs->setInt(3, entity->GetCharacter()->GetID());
|
|
||||||
ugcs->setInt(4, 0);
|
|
||||||
|
|
||||||
//whacky stream biz
|
ugcs->setBlob(5, &iss);
|
||||||
std::string s(sd0Data.get(), sd0Size);
|
ugcs->setBoolean(6, false);
|
||||||
std::istringstream iss(s);
|
ugcs->setString(7, "weedeater.lxfml");
|
||||||
std::istream& stream = iss;
|
ugcs->execute();
|
||||||
|
delete ugcs;
|
||||||
|
|
||||||
ugcs->setBlob(5, &iss);
|
//Insert into the db as a BBB model:
|
||||||
ugcs->setBoolean(6, false);
|
auto* stmt = Database::CreatePreppedStmt("INSERT INTO `properties_contents` VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
|
||||||
ugcs->setString(7, "weedeater.lxfml");
|
stmt->setUInt64(1, newIDL);
|
||||||
ugcs->execute();
|
stmt->setUInt64(2, propertyId);
|
||||||
delete ugcs;
|
stmt->setUInt(3, blueprintIDSmall);
|
||||||
|
stmt->setUInt(4, 14); // 14 is the lot the BBB models use
|
||||||
|
stmt->setDouble(5, 0.0f); // x
|
||||||
|
stmt->setDouble(6, 0.0f); // y
|
||||||
|
stmt->setDouble(7, 0.0f); // z
|
||||||
|
stmt->setDouble(8, 0.0f); // rx
|
||||||
|
stmt->setDouble(9, 0.0f); // ry
|
||||||
|
stmt->setDouble(10, 0.0f); // rz
|
||||||
|
stmt->setDouble(11, 0.0f); // rw
|
||||||
|
stmt->setString(12, "Objects_14_name"); // Model name. TODO make this customizable
|
||||||
|
stmt->setString(13, ""); // Model description. TODO implement this.
|
||||||
|
stmt->setDouble(14, 0); // behavior 1. TODO implement this.
|
||||||
|
stmt->setDouble(15, 0); // behavior 2. TODO implement this.
|
||||||
|
stmt->setDouble(16, 0); // behavior 3. TODO implement this.
|
||||||
|
stmt->setDouble(17, 0); // behavior 4. TODO implement this.
|
||||||
|
stmt->setDouble(18, 0); // behavior 5. TODO implement this.
|
||||||
|
stmt->execute();
|
||||||
|
delete stmt;
|
||||||
|
|
||||||
//Insert into the db as a BBB model:
|
/*
|
||||||
auto* stmt = Database::CreatePreppedStmt("INSERT INTO `properties_contents` VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
|
Commented out until UGC server would be updated to use a sd0 file instead of lxfml stream.
|
||||||
stmt->setUInt64(1, newIDL);
|
(or you uncomment the lxfml decomp stuff above)
|
||||||
stmt->setUInt64(2, propertyId);
|
*/
|
||||||
stmt->setUInt(3, blueprintIDSmall);
|
|
||||||
stmt->setUInt(4, 14); // 14 is the lot the BBB models use
|
|
||||||
stmt->setDouble(5, 0.0f); // x
|
|
||||||
stmt->setDouble(6, 0.0f); // y
|
|
||||||
stmt->setDouble(7, 0.0f); // z
|
|
||||||
stmt->setDouble(8, 0.0f); // rx
|
|
||||||
stmt->setDouble(9, 0.0f); // ry
|
|
||||||
stmt->setDouble(10, 0.0f); // rz
|
|
||||||
stmt->setDouble(11, 0.0f); // rw
|
|
||||||
stmt->setString(12, "Objects_14_name"); // Model name. TODO make this customizable
|
|
||||||
stmt->setString(13, ""); // Model description. TODO implement this.
|
|
||||||
stmt->setDouble(14, 0); // behavior 1. TODO implement this.
|
|
||||||
stmt->setDouble(15, 0); // behavior 2. TODO implement this.
|
|
||||||
stmt->setDouble(16, 0); // behavior 3. TODO implement this.
|
|
||||||
stmt->setDouble(17, 0); // behavior 4. TODO implement this.
|
|
||||||
stmt->setDouble(18, 0); // behavior 5. TODO implement this.
|
|
||||||
stmt->execute();
|
|
||||||
delete stmt;
|
|
||||||
|
|
||||||
/*
|
////Send off to UGC for processing, if enabled:
|
||||||
Commented out until UGC server would be updated to use a sd0 file instead of lxfml stream.
|
//if (Game::config->GetValue("ugc_remote") == "1") {
|
||||||
(or you uncomment the lxfml decomp stuff above)
|
// std::string ugcIP = Game::config->GetValue("ugc_ip");
|
||||||
*/
|
// int ugcPort = std::stoi(Game::config->GetValue("ugc_port"));
|
||||||
|
|
||||||
////Send off to UGC for processing, if enabled:
|
// httplib::Client cli(ugcIP, ugcPort); //connect to UGC HTTP server using our config above ^
|
||||||
//if (Game::config->GetValue("ugc_remote") == "1") {
|
|
||||||
// std::string ugcIP = Game::config->GetValue("ugc_ip");
|
|
||||||
// int ugcPort = std::stoi(Game::config->GetValue("ugc_port"));
|
|
||||||
|
|
||||||
// httplib::Client cli(ugcIP, ugcPort); //connect to UGC HTTP server using our config above ^
|
// //Send out a request:
|
||||||
|
// std::string request = "/3dservices/UGCC150/150" + std::to_string(blueprintID) + ".lxfml";
|
||||||
|
// cli.Put(request.c_str(), lxfml.c_str(), "text/lxfml");
|
||||||
|
|
||||||
// //Send out a request:
|
// //When the "put" above returns, it means that the UGC HTTP server is done processing our model &
|
||||||
// std::string request = "/3dservices/UGCC150/150" + std::to_string(blueprintID) + ".lxfml";
|
// //the nif, hkx and checksum files are ready to be downloaded from cache.
|
||||||
// cli.Put(request.c_str(), lxfml.c_str(), "text/lxfml");
|
//}
|
||||||
|
|
||||||
// //When the "put" above returns, it means that the UGC HTTP server is done processing our model &
|
//Tell the client their model is saved: (this causes us to actually pop out of our current state):
|
||||||
// //the nif, hkx and checksum files are ready to be downloaded from cache.
|
CBITSTREAM;
|
||||||
//}
|
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_SAVE_RESPONSE);
|
||||||
|
bitStream.Write(localId);
|
||||||
|
bitStream.Write(eBlueprintSaveResponseType::EverythingWorked);
|
||||||
|
bitStream.Write<uint32_t>(1);
|
||||||
|
bitStream.Write(blueprintID);
|
||||||
|
|
||||||
//Tell the client their model is saved: (this causes us to actually pop out of our current state):
|
bitStream.Write<uint32_t>(sd0Size);
|
||||||
CBITSTREAM;
|
|
||||||
BitStreamUtils::WriteHeader(bitStream, eConnectionType::CLIENT, eClientMessageType::BLUEPRINT_SAVE_RESPONSE);
|
|
||||||
bitStream.Write(localId);
|
|
||||||
bitStream.Write(eBlueprintSaveResponseType::EverythingWorked);
|
|
||||||
bitStream.Write<uint32_t>(1);
|
|
||||||
bitStream.Write(blueprintID);
|
|
||||||
|
|
||||||
bitStream.Write<uint32_t>(sd0Size);
|
bitStream.WriteAlignedBytes(reinterpret_cast<unsigned char*>(sd0Data.get()), sd0Size);
|
||||||
|
|
||||||
for (size_t i = 0; i < sd0Size; ++i) {
|
SEND_PACKET;
|
||||||
bitStream.Write(sd0Data[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
SEND_PACKET;
|
//Now we have to construct this object:
|
||||||
|
|
||||||
//Now we have to construct this object:
|
EntityInfo info;
|
||||||
|
info.lot = 14;
|
||||||
|
info.pos = {};
|
||||||
|
info.rot = {};
|
||||||
|
info.spawner = nullptr;
|
||||||
|
info.spawnerID = entity->GetObjectID();
|
||||||
|
info.spawnerNodeID = 0;
|
||||||
|
|
||||||
EntityInfo info;
|
LDFBaseData* ldfBlueprintID = new LDFData<LWOOBJID>(u"blueprintid", blueprintID);
|
||||||
info.lot = 14;
|
LDFBaseData* componentWhitelist = new LDFData<int>(u"componentWhitelist", 1);
|
||||||
info.pos = {};
|
LDFBaseData* modelType = new LDFData<int>(u"modelType", 2);
|
||||||
info.rot = {};
|
LDFBaseData* propertyObjectID = new LDFData<bool>(u"propertyObjectID", true);
|
||||||
info.spawner = nullptr;
|
LDFBaseData* userModelID = new LDFData<LWOOBJID>(u"userModelID", newIDL);
|
||||||
info.spawnerID = entity->GetObjectID();
|
|
||||||
info.spawnerNodeID = 0;
|
|
||||||
|
|
||||||
LDFBaseData* ldfBlueprintID = new LDFData<LWOOBJID>(u"blueprintid", blueprintID);
|
info.settings.push_back(ldfBlueprintID);
|
||||||
LDFBaseData* componentWhitelist = new LDFData<int>(u"componentWhitelist", 1);
|
info.settings.push_back(componentWhitelist);
|
||||||
LDFBaseData* modelType = new LDFData<int>(u"modelType", 2);
|
info.settings.push_back(modelType);
|
||||||
LDFBaseData* propertyObjectID = new LDFData<bool>(u"propertyObjectID", true);
|
info.settings.push_back(propertyObjectID);
|
||||||
LDFBaseData* userModelID = new LDFData<LWOOBJID>(u"userModelID", newIDL);
|
info.settings.push_back(userModelID);
|
||||||
|
|
||||||
info.settings.push_back(ldfBlueprintID);
|
Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
|
||||||
info.settings.push_back(componentWhitelist);
|
if (newEntity) {
|
||||||
info.settings.push_back(modelType);
|
Game::entityManager->ConstructEntity(newEntity);
|
||||||
info.settings.push_back(propertyObjectID);
|
|
||||||
info.settings.push_back(userModelID);
|
|
||||||
|
|
||||||
Entity* newEntity = Game::entityManager->CreateEntity(info, nullptr);
|
//Make sure the propMgmt doesn't delete our model after the server dies
|
||||||
if (newEntity) {
|
//Trying to do this after the entity is constructed. Shouldn't really change anything but
|
||||||
Game::entityManager->ConstructEntity(newEntity);
|
//there was an issue with builds not appearing since it was placed above ConstructEntity.
|
||||||
|
PropertyManagementComponent::Instance()->AddModel(newEntity->GetObjectID(), newIDL);
|
||||||
|
}
|
||||||
|
|
||||||
//Make sure the propMgmt doesn't delete our model after the server dies
|
});
|
||||||
//Trying to do this after the entity is constructed. Shouldn't really change anything but
|
|
||||||
//there was an issue with builds not appearing since it was placed above ConstructEntity.
|
|
||||||
PropertyManagementComponent::Instance()->AddModel(newEntity->GetObjectID(), newIDL);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
|
void GameMessages::HandlePropertyEntranceSync(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr) {
|
||||||
@ -5645,10 +5630,18 @@ void GameMessages::HandleModularBuildFinish(RakNet::BitStream* inStream, Entity*
|
|||||||
std::vector<LDFBaseData*> config;
|
std::vector<LDFBaseData*> config;
|
||||||
config.push_back(moduleAssembly);
|
config.push_back(moduleAssembly);
|
||||||
|
|
||||||
|
LWOOBJID newIdBig;
|
||||||
|
// Make sure a subkey isnt already in use. Persistent Ids do not make sense here since this only needs to be unique for
|
||||||
|
// this character. Because of that, we just generate a random id and check for a collision.
|
||||||
|
do {
|
||||||
|
newIdBig = ObjectIDManager::Instance()->GenerateRandomObjectID();
|
||||||
|
GeneralUtils::SetBit(newIdBig, eObjectBits::CHARACTER);
|
||||||
|
} while (inv->FindItemBySubKey(newIdBig));
|
||||||
|
|
||||||
if (count == 3) {
|
if (count == 3) {
|
||||||
inv->AddItem(6416, 1, eLootSourceType::QUICKBUILD, eInventoryType::MODELS, config);
|
inv->AddItem(6416, 1, eLootSourceType::QUICKBUILD, eInventoryType::MODELS, config, LWOOBJID_EMPTY, true, false, newIdBig);
|
||||||
} else if (count == 7) {
|
} else if (count == 7) {
|
||||||
inv->AddItem(8092, 1, eLootSourceType::QUICKBUILD, eInventoryType::MODELS, config);
|
inv->AddItem(8092, 1, eLootSourceType::QUICKBUILD, eInventoryType::MODELS, config, LWOOBJID_EMPTY, true, false, newIdBig);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* missionComponent = character->GetComponent<MissionComponent>();
|
auto* missionComponent = character->GetComponent<MissionComponent>();
|
||||||
|
@ -29,7 +29,7 @@ void ReportCheat(User* user, const SystemAddress& sysAddr, const char* messageIf
|
|||||||
std::unique_ptr<sql::PreparedStatement> stmt(Database::CreatePreppedStmt(
|
std::unique_ptr<sql::PreparedStatement> stmt(Database::CreatePreppedStmt(
|
||||||
"INSERT INTO player_cheat_detections (account_id, name, violation_msg, violation_system_address) VALUES (?, ?, ?, ?)")
|
"INSERT INTO player_cheat_detections (account_id, name, violation_msg, violation_system_address) VALUES (?, ?, ?, ?)")
|
||||||
);
|
);
|
||||||
stmt->setInt(1, user ? user->GetAccountID() : 0);
|
user ? stmt->setInt(1, user->GetAccountID()) : stmt->setNull(1, sql::DataType::INTEGER);
|
||||||
stmt->setString(2, user ? user->GetUsername().c_str() : "User is null.");
|
stmt->setString(2, user ? user->GetUsername().c_str() : "User is null.");
|
||||||
|
|
||||||
constexpr int32_t bufSize = 4096;
|
constexpr int32_t bufSize = 4096;
|
||||||
|
@ -154,7 +154,7 @@ int main(int argc, char** argv) {
|
|||||||
Game::assetManager = new AssetManager(clientPath);
|
Game::assetManager = new AssetManager(clientPath);
|
||||||
} catch (std::runtime_error& ex) {
|
} catch (std::runtime_error& ex) {
|
||||||
LOG("Got an error while setting up assets: %s", ex.what());
|
LOG("Got an error while setting up assets: %s", ex.what());
|
||||||
|
LOG("Is the provided client_location in Windows Onedrive? If so, remove it from Onedrive.");
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#include "MissionComponent.h"
|
#include "MissionComponent.h"
|
||||||
#include "SkillComponent.h"
|
#include "SkillComponent.h"
|
||||||
#include "eMissionTaskType.h"
|
#include "eMissionTaskType.h"
|
||||||
|
#include "CDClientManager.h"
|
||||||
|
#include "CDObjectSkillsTable.h"
|
||||||
#include "RenderComponent.h"
|
#include "RenderComponent.h"
|
||||||
|
|
||||||
//TODO: this has to be updated so that you only get killed if you're in a certain radius.
|
//TODO: this has to be updated so that you only get killed if you're in a certain radius.
|
||||||
@ -39,9 +41,11 @@ void ExplodingAsset::OnHit(Entity* self, Entity* attacker) {
|
|||||||
self->SetOwnerOverride(attacker->GetObjectID());
|
self->SetOwnerOverride(attacker->GetObjectID());
|
||||||
|
|
||||||
GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(self, u"camshake", self->GetObjectID(), 16);
|
GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(self, u"camshake", self->GetObjectID(), 16);
|
||||||
|
self->Smash(attacker->GetObjectID());
|
||||||
|
|
||||||
auto* skillComponent = self->GetComponent<SkillComponent>();
|
auto* skillComponent = self->GetComponent<SkillComponent>();
|
||||||
if (skillComponent != nullptr) {
|
if (skillComponent != nullptr) {
|
||||||
|
// Technically supposed to get first skill in the skill component but only 1 object in the live game used this.
|
||||||
skillComponent->CalculateBehavior(147, 4721, LWOOBJID_EMPTY, true);
|
skillComponent->CalculateBehavior(147, 4721, LWOOBJID_EMPTY, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,8 +69,6 @@ void ExplodingAsset::OnHit(Entity* self, Entity* attacker) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self->ScheduleKillAfterUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExplodingAsset::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) {
|
void ExplodingAsset::OnProximityUpdate(Entity* self, Entity* entering, std::string name, std::string status) {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "NtCombatChallengeExplodingDummy.h"
|
#include "NtCombatChallengeExplodingDummy.h"
|
||||||
#include "EntityManager.h"
|
#include "EntityManager.h"
|
||||||
#include "SkillComponent.h"
|
#include "SkillComponent.h"
|
||||||
|
#include "DestroyableComponent.h"
|
||||||
|
|
||||||
void NtCombatChallengeExplodingDummy::OnDie(Entity* self, Entity* killer) {
|
void NtCombatChallengeExplodingDummy::OnDie(Entity* self, Entity* killer) {
|
||||||
const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID");
|
const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID");
|
||||||
@ -15,6 +16,17 @@ void NtCombatChallengeExplodingDummy::OnDie(Entity* self, Entity* killer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void NtCombatChallengeExplodingDummy::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {
|
void NtCombatChallengeExplodingDummy::OnHitOrHealResult(Entity* self, Entity* attacker, int32_t damage) {
|
||||||
|
auto* destroyableComponent = self->GetComponent<DestroyableComponent>();
|
||||||
|
auto numTimesHit = self->GetVar<int32_t>(u"numTimesHit");
|
||||||
|
if (destroyableComponent && numTimesHit == 0) {
|
||||||
|
self->SetVar<int32_t>(u"numTimesHit", 1);
|
||||||
|
destroyableComponent->SetHealth(destroyableComponent->GetHealth() / 2);
|
||||||
|
return;
|
||||||
|
} else if (numTimesHit == 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self->SetVar<int32_t>(u"numTimesHit", 2);
|
||||||
|
|
||||||
const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID");
|
const auto challengeObjectID = self->GetVar<LWOOBJID>(u"challengeObjectID");
|
||||||
|
|
||||||
auto* challengeObject = Game::entityManager->GetEntity(challengeObjectID);
|
auto* challengeObject = Game::entityManager->GetEntity(challengeObjectID);
|
||||||
@ -28,5 +40,6 @@ void NtCombatChallengeExplodingDummy::OnHitOrHealResult(Entity* self, Entity* at
|
|||||||
if (skillComponent != nullptr) {
|
if (skillComponent != nullptr) {
|
||||||
skillComponent->CalculateBehavior(1338, 30875, attacker->GetObjectID());
|
skillComponent->CalculateBehavior(1338, 30875, attacker->GetObjectID());
|
||||||
}
|
}
|
||||||
self->Kill(attacker);
|
GameMessages::SendPlayEmbeddedEffectOnAllClientsNearObject(self, u"camshake", self->GetObjectID(), 16.0f);
|
||||||
|
self->Smash(attacker->GetObjectID());
|
||||||
}
|
}
|
||||||
|
@ -938,7 +938,7 @@ void HandlePacket(Packet* packet) {
|
|||||||
//We need to delete the entity first, otherwise the char list could delete it while it exists in the world!
|
//We need to delete the entity first, otherwise the char list could delete it while it exists in the world!
|
||||||
if (Game::server->GetZoneID() != 0) {
|
if (Game::server->GetZoneID() != 0) {
|
||||||
auto user = UserManager::Instance()->GetUser(packet->systemAddress);
|
auto user = UserManager::Instance()->GetUser(packet->systemAddress);
|
||||||
if (!user) return;
|
if (!user || !user->GetLastUsedChar()) return;
|
||||||
Game::entityManager->DestroyEntity(user->GetLastUsedChar()->GetEntity());
|
Game::entityManager->DestroyEntity(user->GetLastUsedChar()->GetEntity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Binary file not shown.
19
systemd.example
Normal file
19
systemd.example
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[Unit]
|
||||||
|
# Description of the service.
|
||||||
|
Description=Darkflame LEGO Universe Server
|
||||||
|
# Wait for network to start first before starting this service.
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
# Services should have their own, dedicated, user account.
|
||||||
|
# The specific user that our service will run as, you can find your current user by issuing `id -un`
|
||||||
|
User=darkflame
|
||||||
|
# The specific group that our service will run as, you can find your current primary group by issuing `id -gn`
|
||||||
|
Group=darkflame
|
||||||
|
# Full Path to the darkflame server process
|
||||||
|
ExecStart=/PATH/TO/DarkflameServer/build/MasterServer
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
# Define the behavior if the service is enabled or disabled to automatically started at boot.
|
||||||
|
WantedBy=multi-user.target
|
Loading…
Reference in New Issue
Block a user