Merge branch 'develop' into fail2ban-experiment
This commit is contained in:
commit
1b2237982e
27
.github/workflows/build.yml
vendored
27
.github/workflows/build.yml
vendored
@ -51,30 +51,3 @@ jobs:
|
|||||||
build/bin/Win32/${{matrix.configuration}}/iw4x.dll
|
build/bin/Win32/${{matrix.configuration}}/iw4x.dll
|
||||||
build/bin/Win32/${{matrix.configuration}}/iw4x.pdb
|
build/bin/Win32/${{matrix.configuration}}/iw4x.pdb
|
||||||
|
|
||||||
deploy:
|
|
||||||
name: Deploy artifacts
|
|
||||||
needs: build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/develop')
|
|
||||||
steps:
|
|
||||||
- name: Setup develop environment
|
|
||||||
if: github.ref == 'refs/heads/develop'
|
|
||||||
run: echo "DIAMANTE_MASTER_PATH=${{ secrets.DIAMANTE_MASTER_SSH_PATH }}" >> $GITHUB_ENV
|
|
||||||
|
|
||||||
- name: Download Release binaries
|
|
||||||
uses: actions/download-artifact@v3.0.2
|
|
||||||
with:
|
|
||||||
name: Release binaries
|
|
||||||
|
|
||||||
# Set up committer info and GPG key
|
|
||||||
- name: Install SSH key
|
|
||||||
uses: shimataro/ssh-key-action@v2.5.1
|
|
||||||
with:
|
|
||||||
key: ${{ secrets.DIAMANTE_MASTER_SSH_PRIVATE_KEY }}
|
|
||||||
known_hosts: 'just-a-placeholder-so-we-dont-get-errors'
|
|
||||||
|
|
||||||
- name: Add known hosts
|
|
||||||
run: ssh-keyscan -H ${{ secrets.DIAMANTE_MASTER_SSH_ADDRESS }} >> ~/.ssh/known_hosts
|
|
||||||
|
|
||||||
- name: Upload iw4x-client binary
|
|
||||||
run: rsync -avz iw4x.dll ${{ secrets.DIAMANTE_MASTER_SSH_USER }}@${{ secrets.DIAMANTE_MASTER_SSH_ADDRESS }}:${{ env.DIAMANTE_MASTER_PATH }}/legacy/
|
|
||||||
|
2
deps/GSL
vendored
2
deps/GSL
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 4300304ef24c247b3db0255763f46b9f95c3a83d
|
Subproject commit e64c97fc2cfc11992098bb38eda932de275e3f4d
|
2
deps/iw4-open-formats
vendored
2
deps/iw4-open-formats
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 700a2ae858c27568d95e21ce8c5f941d36c4a6c4
|
Subproject commit f174f1c4c4c465c337166b92e03b355695c5bc93
|
2
deps/libtommath
vendored
2
deps/libtommath
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 3746c58f29a1ebea15046932bbc9dacc35b4b214
|
Subproject commit 8314bde5e5c8e5d9331460130a9d1066e324f091
|
@ -224,6 +224,18 @@ namespace Components
|
|||||||
|
|
||||||
void AssetHandler::ModifyAsset(Game::XAssetType type, Game::XAssetHeader asset, const std::string& name)
|
void AssetHandler::ModifyAsset(Game::XAssetType type, Game::XAssetHeader asset, const std::string& name)
|
||||||
{
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (type == Game::XAssetType::ASSET_TYPE_IMAGE && name[0] != ',')
|
||||||
|
{
|
||||||
|
const auto image = asset.image;
|
||||||
|
const auto cat = static_cast<Game::ImageCategory>(image->category);
|
||||||
|
if (cat == Game::ImageCategory::IMG_CATEGORY_UNKNOWN)
|
||||||
|
{
|
||||||
|
Logger::Warning(Game::CON_CHANNEL_GFX, "Image {} has wrong category IMG_CATEGORY_UNKNOWN, this is an IMPORTANT ISSUE that should be fixed!\n", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (type == Game::ASSET_TYPE_MATERIAL && (name == "gfx_distortion_knife_trail" || name == "gfx_distortion_heat_far" || name == "gfx_distortion_ring_light" || name == "gfx_distortion_heat") && asset.material->info.sortKey >= 43)
|
if (type == Game::ASSET_TYPE_MATERIAL && (name == "gfx_distortion_knife_trail" || name == "gfx_distortion_heat_far" || name == "gfx_distortion_ring_light" || name == "gfx_distortion_heat") && asset.material->info.sortKey >= 43)
|
||||||
{
|
{
|
||||||
if (Zones::Version() >= VERSION_ALPHA2)
|
if (Zones::Version() >= VERSION_ALPHA2)
|
||||||
|
@ -396,6 +396,7 @@ namespace Assets
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buffer->align(Utils::Stream::ALIGN_4);
|
||||||
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
|
buffer->saveMax(sizeof(Game::snd_alias_list_t*));
|
||||||
buffer->saveString(def->bounceSound[i]->aliasName);
|
buffer->saveString(def->bounceSound[i]->aliasName);
|
||||||
}
|
}
|
||||||
@ -525,7 +526,7 @@ namespace Assets
|
|||||||
|
|
||||||
if (def->physCollmap)
|
if (def->physCollmap)
|
||||||
{
|
{
|
||||||
dest->physCollmap = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_PHYSCOLLMAP, def->overlayMaterialEMPLowRes).physCollmap;
|
dest->physCollmap = builder->saveSubAsset(Game::XAssetType::ASSET_TYPE_PHYSCOLLMAP, def->physCollmap).physCollmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (def->projectileModel)
|
if (def->projectileModel)
|
||||||
|
@ -205,8 +205,7 @@ namespace Components
|
|||||||
|
|
||||||
void Maps::LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, const std::string& name, bool* restrict)
|
void Maps::LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, const std::string& name, bool* restrict)
|
||||||
{
|
{
|
||||||
if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), FastFiles::Current()) != Maps::CurrentDependencies.end()
|
if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), FastFiles::Current()) != Maps::CurrentDependencies.end()) // Shipment is a special case
|
||||||
&& (FastFiles::Current() != "mp_shipment_long" || Maps::CurrentMainZone != "mp_shipment")) // Shipment is a special case
|
|
||||||
{
|
{
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
@ -315,6 +314,7 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO : Remove hook entirely?
|
||||||
void Maps::GetBSPName(char* buffer, size_t size, const char* format, const char* mapname)
|
void Maps::GetBSPName(char* buffer, size_t size, const char* format, const char* mapname)
|
||||||
{
|
{
|
||||||
if (!Utils::String::StartsWith(mapname, "mp_"))
|
if (!Utils::String::StartsWith(mapname, "mp_"))
|
||||||
@ -322,12 +322,6 @@ namespace Components
|
|||||||
format = "maps/%s.d3dbsp";
|
format = "maps/%s.d3dbsp";
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Remove this hack by using CoD4 version of the map
|
|
||||||
if (std::strcmp(mapname, "mp_shipment") == 0)
|
|
||||||
{
|
|
||||||
mapname = "mp_shipment_long";
|
|
||||||
}
|
|
||||||
|
|
||||||
_snprintf_s(buffer, size, _TRUNCATE, format, mapname);
|
_snprintf_s(buffer, size, _TRUNCATE, format, mapname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,7 +382,7 @@ namespace Components
|
|||||||
auto world = gfxAsset->asset.header.gfxWorld;
|
auto world = gfxAsset->asset.header.gfxWorld;
|
||||||
|
|
||||||
auto drawDistance = r_playerDrawDebugDistance.get<int>();
|
auto drawDistance = r_playerDrawDebugDistance.get<int>();
|
||||||
auto sqrDist = drawDistance * drawDistance;
|
auto sqrDist = drawDistance * static_cast<float>(drawDistance);
|
||||||
|
|
||||||
switch (val)
|
switch (val)
|
||||||
{
|
{
|
||||||
|
@ -73,12 +73,12 @@ namespace Components
|
|||||||
|
|
||||||
// Sort alphabetically
|
// Sort alphabetically
|
||||||
qsort(indices, dataVector.size(), sizeof(Game::StructuredDataEnumEntry), [](void const* first, void const* second)
|
qsort(indices, dataVector.size(), sizeof(Game::StructuredDataEnumEntry), [](void const* first, void const* second)
|
||||||
{
|
{
|
||||||
const Game::StructuredDataEnumEntry* entry1 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(first);
|
const Game::StructuredDataEnumEntry* entry1 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(first);
|
||||||
const Game::StructuredDataEnumEntry* entry2 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(second);
|
const Game::StructuredDataEnumEntry* entry2 = reinterpret_cast<const Game::StructuredDataEnumEntry*>(second);
|
||||||
|
|
||||||
return std::string(entry1->string).compare(entry2->string);
|
return std::string(entry1->string).compare(entry2->string);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Apply our patches
|
// Apply our patches
|
||||||
dataEnum->entryCount = dataVector.size();
|
dataEnum->entryCount = dataVector.size();
|
||||||
@ -117,7 +117,7 @@ namespace Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StructuredData::UpdateVersionOffsets(Game::StructuredDataDefSet *set, Game::StructuredDataBuffer *buffer, Game::StructuredDataDef *whatever)
|
bool StructuredData::UpdateVersionOffsets(Game::StructuredDataDefSet* set, Game::StructuredDataBuffer* buffer, Game::StructuredDataDef* whatever)
|
||||||
{
|
{
|
||||||
Game::StructuredDataDef* newDef = &set->defs[0];
|
Game::StructuredDataDef* newDef = &set->defs[0];
|
||||||
Game::StructuredDataDef* oldDef = &set->defs[0];
|
Game::StructuredDataDef* oldDef = &set->defs[0];
|
||||||
@ -149,10 +149,165 @@ namespace Components
|
|||||||
{
|
{
|
||||||
if (Dedicated::IsEnabled()) return;
|
if (Dedicated::IsEnabled()) return;
|
||||||
|
|
||||||
// Correctly upgrade stats
|
// Do not execute this when building zones
|
||||||
Utils::Hook(0x42F088, StructuredData::UpdateVersionOffsets, HOOK_CALL).install()->quick();
|
if (!ZoneBuilder::IsEnabled())
|
||||||
|
{
|
||||||
|
// Correctly upgrade stats
|
||||||
|
Utils::Hook(0x42F088, StructuredData::UpdateVersionOffsets, HOOK_CALL).install()->quick();
|
||||||
|
|
||||||
// 15 or more custom classes
|
// 15 or more custom classes
|
||||||
Utils::Hook::Set<BYTE>(0x60A2FE, NUM_CUSTOM_CLASSES);
|
Utils::Hook::Set<BYTE>(0x60A2FE, NUM_CUSTOM_CLASSES);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Since all of the following is zonebuilder-only code, move it to IW4OF or IStructuredDataDefSet.cpp
|
||||||
|
AssetHandler::OnLoad([](Game::XAssetType type, Game::XAssetHeader asset, const std::string& filename, bool* /*restrict*/)
|
||||||
|
{
|
||||||
|
if (ZoneBuilder::IsDumpingZone()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only intercept playerdatadef loading
|
||||||
|
if (type != Game::ASSET_TYPE_STRUCTURED_DATA_DEF || filename != "mp/playerdata.def") return;
|
||||||
|
|
||||||
|
// Store asset
|
||||||
|
Game::StructuredDataDefSet* data = asset.structuredDataDefSet;
|
||||||
|
if (!data) return;
|
||||||
|
|
||||||
|
if (data->defCount != 1)
|
||||||
|
{
|
||||||
|
Logger::Error(Game::ERR_FATAL, "PlayerDataDefSet contains more than 1 definition!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->defs[0].version != 155)
|
||||||
|
{
|
||||||
|
Logger::Error(Game::ERR_FATAL, "Initial PlayerDataDef is not version 155, patching not possible!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_map<int, std::vector<std::vector<std::string>>> patchDefinitions;
|
||||||
|
std::unordered_map<int, std::unordered_map<std::string, std::string>> otherPatchDefinitions;
|
||||||
|
|
||||||
|
// First check if all versions are present
|
||||||
|
for (int i = 156;; ++i)
|
||||||
|
{
|
||||||
|
// We're on DB thread (OnLoad) so use DB thread for FS
|
||||||
|
FileSystem::File definition(std::format("{}/{}.json", filename, i), Game::FsThread::FS_THREAD_DATABASE);
|
||||||
|
if (!definition.exists()) break;
|
||||||
|
|
||||||
|
std::vector<std::vector<std::string>> enumContainer;
|
||||||
|
std::unordered_map<std::string, std::string> otherPatches;
|
||||||
|
|
||||||
|
nlohmann::json defData;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
defData = nlohmann::json::parse(definition.getBuffer());
|
||||||
|
}
|
||||||
|
catch (const nlohmann::json::parse_error& ex)
|
||||||
|
{
|
||||||
|
Logger::PrintError(Game::CON_CHANNEL_ERROR, "JSON Parse Error: {}\n", ex.what());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!defData.is_object())
|
||||||
|
{
|
||||||
|
Logger::Error(Game::ERR_FATAL, "PlayerDataDef patch for version {} is invalid!", i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto pType = 0; pType < StructuredData::PlayerDataType::COUNT; ++pType)
|
||||||
|
{
|
||||||
|
auto enumData = defData[StructuredData::EnumTranslation[pType]];
|
||||||
|
|
||||||
|
std::vector<std::string> entryData;
|
||||||
|
|
||||||
|
if (enumData.is_array())
|
||||||
|
{
|
||||||
|
for (const auto& rawEntry : enumData)
|
||||||
|
{
|
||||||
|
if (rawEntry.is_string())
|
||||||
|
{
|
||||||
|
entryData.push_back(rawEntry.get<std::string>());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enumContainer.push_back(entryData);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto other = defData["other"];
|
||||||
|
|
||||||
|
if (other.is_object())
|
||||||
|
{
|
||||||
|
for (auto& item : other.items())
|
||||||
|
{
|
||||||
|
if (item.value().is_string())
|
||||||
|
{
|
||||||
|
otherPatches[item.key()] = item.value().get<std::string>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
patchDefinitions[i] = enumContainer;
|
||||||
|
otherPatchDefinitions[i] = otherPatches;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing to patch
|
||||||
|
if (patchDefinitions.empty()) return;
|
||||||
|
|
||||||
|
// Reallocate the definition
|
||||||
|
auto* newData = StructuredData::MemAllocator.allocateArray<Game::StructuredDataDef>(data->defCount + patchDefinitions.size());
|
||||||
|
std::memcpy(&newData[patchDefinitions.size()], data->defs, sizeof Game::StructuredDataDef * data->defCount);
|
||||||
|
|
||||||
|
// Prepare the buffers
|
||||||
|
for (unsigned int i = 0; i < patchDefinitions.size(); ++i)
|
||||||
|
{
|
||||||
|
std::memcpy(&newData[i], data->defs, sizeof Game::StructuredDataDef);
|
||||||
|
newData[i].version = (patchDefinitions.size() - i) + 155;
|
||||||
|
|
||||||
|
// Reallocate the enum array
|
||||||
|
auto* newEnums = StructuredData::MemAllocator.allocateArray<Game::StructuredDataEnum>(data->defs->enumCount);
|
||||||
|
std::memcpy(newEnums, data->defs->enums, sizeof Game::StructuredDataEnum * data->defs->enumCount);
|
||||||
|
newData[i].enums = newEnums;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply new data
|
||||||
|
data->defs = newData;
|
||||||
|
data->defCount += patchDefinitions.size();
|
||||||
|
|
||||||
|
// Patch the definition
|
||||||
|
for (unsigned int i = 0; i < data->defCount; ++i)
|
||||||
|
{
|
||||||
|
// No need to patch version 155
|
||||||
|
if (newData[i].version == 155) continue;
|
||||||
|
|
||||||
|
if (patchDefinitions.contains(newData[i].version))
|
||||||
|
{
|
||||||
|
auto patchData = patchDefinitions[newData[i].version];
|
||||||
|
auto otherData = otherPatchDefinitions[newData[i].version];
|
||||||
|
|
||||||
|
// Invalid patch data
|
||||||
|
if (patchData.size() != StructuredData::PlayerDataType::COUNT)
|
||||||
|
{
|
||||||
|
Logger::Error(Game::ERR_FATAL, "PlayerDataDef patch for version {} wasn't parsed correctly!", newData[i].version);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the patch data
|
||||||
|
for (auto pType = 0; pType < StructuredData::PlayerDataType::COUNT; ++pType)
|
||||||
|
{
|
||||||
|
if (!patchData[pType].empty())
|
||||||
|
{
|
||||||
|
StructuredData::PatchPlayerDataEnum(&newData[i], static_cast<StructuredData::PlayerDataType>(pType), patchData[pType]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StructuredData::PatchAdditionalData(&newData[i], otherData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,6 +129,7 @@ namespace Components
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool IsEnabled();
|
static bool IsEnabled();
|
||||||
|
static bool IsDumpingZone() { return DumpingZone.length() > 0; };
|
||||||
|
|
||||||
static std::string TraceZone;
|
static std::string TraceZone;
|
||||||
static std::vector<std::pair<Game::XAssetType, std::string>> TraceAssets;
|
static std::vector<std::pair<Game::XAssetType, std::string>> TraceAssets;
|
||||||
@ -142,7 +143,7 @@ namespace Components
|
|||||||
static iw4of::api* GetExporter();
|
static iw4of::api* GetExporter();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static int StoreTexture(Game::GfxImageLoadDef **loadDef, Game::GfxImage *image);
|
static int StoreTexture(Game::GfxImageLoadDef** loadDef, Game::GfxImage* image);
|
||||||
static void ReleaseTexture(Game::XAssetHeader header);
|
static void ReleaseTexture(Game::XAssetHeader header);
|
||||||
|
|
||||||
static std::string FindMaterialByTechnique(const std::string& name);
|
static std::string FindMaterialByTechnique(const std::string& name);
|
||||||
|
Loading…
Reference in New Issue
Block a user