Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Add commonly requested multiplayer visibility options (with server approval required) #285

Closed
wants to merge 9 commits into from
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,12 @@ Configuration example:
$DF Force Player Character: "enviro_parker"
// Maximal horizontal FOV that clients can use for level rendering (unlimited by default)
//$DF Max FOV: 125
// Allow clients to use `mesh_fullbright`
$DF Allow Fullbright Meshes: false
// Allow clients to use `lightmaps_only`
$DF Allow Lightmaps Only Mode: false
// Allow clients to use `disable_screenshake`
$DF Allow Disable Screenshake: false
// If enabled a private message with player statistics is sent after each round.
//$DF Send Player Stats Message: true
// Send a chat message to players when they join the server ($PLAYER is replaced by player name)
Expand Down
4 changes: 4 additions & 0 deletions common/include/common/config/GameConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ struct GameConfig
CfgVar<bool> glares = true;
CfgVar<bool> show_enemy_bullets = true;

CfgVar<bool> try_mesh_fullbright = false;
CfgVar<bool> try_lightmaps_only = false;
CfgVar<bool> try_disable_screenshake = false;

static constexpr float min_fov = 75.0f;
static constexpr float max_fov = 160.0f;
CfgVar<float> horz_fov{0.0f, [](float val) { return val == 0.0f ? 0.0f : std::clamp(val, min_fov, max_fov); }};
Expand Down
3 changes: 3 additions & 0 deletions common/src/config/GameConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ bool GameConfig::visit_vars(T&& visitor, bool is_save)
result &= visitor(dash_faction_key, "Glares", glares);
result &= visitor(dash_faction_key, "Linear Pitch", linear_pitch);
result &= visitor(dash_faction_key, "Show Enemy Bullets", show_enemy_bullets);
result &= visitor(dash_faction_key, "Lightmaps Only", try_lightmaps_only);
result &= visitor(dash_faction_key, "Fullbright Meshes", try_mesh_fullbright);
result &= visitor(dash_faction_key, "Disable Screenshake", try_disable_screenshake);
result &= visitor(dash_faction_key, "Keep Launcher Open", keep_launcher_open);
result &= visitor(dash_faction_key, "Skip Cutscene Control", skip_cutscene_ctrl);
result &= visitor(dash_faction_key, "Damage Screen Flash", damage_screen_flash);
Expand Down
2 changes: 2 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ Version 1.9.0 (not released yet)
- Do not load unnecessary VPPs in dedicated server mode
- Add level filename to "Level Initializing" console message
- Properly handle WM_PAINT in dedicated server, may improve performance (DF bug)
- Add `lightmaps_only`, `mesh_fullbright`, and `disable_screenshake` commands
- Add `$DF Allow Lightmaps Only Mode`, `$DF Allow Fullbright Meshes`, and `$DF Allow Disable Screenshake` dedicated server config options

Version 1.8.0 (released 2022-09-17)
-----------------------------------
Expand Down
38 changes: 38 additions & 0 deletions game_patch/graphics/gr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
#include <patch_common/CodeInjection.h>
#include <patch_common/ShortTypes.h>
#include <patch_common/AsmWriter.h>
#include <xlog/xlog.h>
#include "../os/console.h"
#include "../main/main.h"
#include "../multi/multi.h"
#include "../rf/gr/gr.h"
#include "../rf/level.h"
#include "../rf/geometry.h"
#include "../rf/player/player.h"
#include "../rf/multi.h"
#include "../rf/os/os.h"
Expand Down Expand Up @@ -144,6 +147,40 @@ ConsoleCommand2 gamma_cmd{
"gamma [value]",
};

void evaluate_lightmaps_only()
{
bool server_side_restrict_lightmaps_only =
rf::is_multi && !rf::is_server && get_df_server_info() && !get_df_server_info()->allow_lmap;

if (server_side_restrict_lightmaps_only) {
if (g_game_config.try_lightmaps_only) {
rf::console::print("This server does not allow you to use lightmap only mode!");
rf::gr::show_lightmaps = false;
rf::g_cache_clear();
}
}
else {
if (rf::gr::show_lightmaps != g_game_config.try_lightmaps_only) {
rf::gr::show_lightmaps = g_game_config.try_lightmaps_only;
rf::g_cache_clear();
}
}
}

ConsoleCommand2 lightmaps_only_cmd{
"lightmaps_only",
[]() {
g_game_config.try_lightmaps_only = !g_game_config.try_lightmaps_only;
g_game_config.save();

evaluate_lightmaps_only();

rf::console::print("Lightmap only mode is {}", g_game_config.try_lightmaps_only ?
"enabled. In multiplayer, this will only apply if the server allows it." : "disabled.");
},
"Render only lightmaps for level geometry (no textures). In multiplayer, this is only available if the server allows it.",
};

FunHook<float(const rf::Vector3&)> gr_get_apparent_distance_from_camera_hook{
0x005182F0,
[](const rf::Vector3& pos) {
Expand Down Expand Up @@ -326,6 +363,7 @@ void gr_apply_patch()
// Commands
fov_cmd.register_cmd();
gamma_cmd.register_cmd();
lightmaps_only_cmd.register_cmd();
fullscreen_cmd.register_cmd();
windowed_cmd.register_cmd();
nearest_texture_filtering_cmd.register_cmd();
Expand Down
1 change: 1 addition & 0 deletions game_patch/graphics/gr.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../rf/gr/gr.h"

void gr_apply_patch();
void evaluate_lightmaps_only();
int gr_font_get_default();
void gr_font_set_default(int font_id);
bool gr_set_render_target(int bm_handle);
Expand Down
7 changes: 7 additions & 0 deletions game_patch/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,13 @@ FunHook<void(bool)> level_init_post_hook{
[](bool transition) {
level_init_post_hook.call_target(transition);
xlog::info("Level loaded: {}{}", rf::level.filename, transition ? " (transition)" : "");
evaluate_fullbright_meshes();
if (g_game_config.try_lightmaps_only) {
evaluate_lightmaps_only();
}
if (g_game_config.try_disable_screenshake) {
evaluate_restrict_disable_ss();
}
},
};

Expand Down
2 changes: 2 additions & 0 deletions game_patch/main/main.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@ extern GameConfig g_game_config;
#ifdef _WINDOWS_
extern HMODULE g_hmodule;
#endif

void evaluate_fullbright_meshes();
52 changes: 52 additions & 0 deletions game_patch/misc/camera.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
#include <patch_common/AsmWriter.h>
#include <patch_common/FunHook.h>
#include "../main/main.h"
#include "../rf/multi.h"
#include "../os/console.h"
#include "../misc/misc.h"
#include "../multi/multi.h"
#include "../rf/player/player.h"
#include "../rf/os/frametime.h"

constexpr auto screen_shake_fps = 150.0f;

static float g_camera_shake_factor = 0.6f;

bool server_side_restrict_disable_ss = false;

FunHook<void(rf::Camera*)> camera_update_shake_hook{
0x0040DB70,
[](rf::Camera *camera) {
Expand All @@ -20,11 +27,56 @@ FunHook<void(rf::Camera*)> camera_update_shake_hook{
},
};

// called whenever screenshake is used, weapons, explosions, fall damage, events, etc.
FunHook<void(rf::Camera*, float, float)> camera_shake_hook{
0x0040E0B0,
[](rf::Camera* cp, float amplitude, float time_seconds) {

if (g_game_config.try_disable_screenshake && !server_side_restrict_disable_ss) {
return;
}

camera_shake_hook.call_target(cp, amplitude, time_seconds);
}
};

void evaluate_restrict_disable_ss()
{
server_side_restrict_disable_ss =
rf::is_multi && !rf::is_server && get_df_server_info() && !get_df_server_info()->allow_no_ss;

if (server_side_restrict_disable_ss) {
if (g_game_config.try_disable_screenshake) {
rf::console::print("This server does not allow you to disable screenshake!");
}
}
}

ConsoleCommand2 disable_screenshake_cmd{
"disable_screenshake",
[]() {
g_game_config.try_disable_screenshake = !g_game_config.try_disable_screenshake;
g_game_config.save();

evaluate_restrict_disable_ss();

rf::console::print("Screenshake is {}",
g_game_config.try_disable_screenshake
? "disabled. In multiplayer, this will only apply if the server allows it."
: "enabled.");
},
"Disable screenshake. In multiplayer, this is only applied if the server allows it.",
};

void camera_do_patch()
{
// Fix crash when executing camera2 command in main menu
AsmWriter(0x0040DCFC).nop(5);

// Fix screen shake caused by some weapons (eg. Assault Rifle)
write_mem_ptr(0x0040DBCC + 2, &g_camera_shake_factor);

// handle turning off screen shake
disable_screenshake_cmd.register_cmd();
camera_shake_hook.install();
}
1 change: 1 addition & 0 deletions game_patch/misc/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ void start_join_multi_game_sequence(const rf::NetAddr& addr, const std::string&
bool multi_join_game(const rf::NetAddr& addr, const std::string& password);
void ui_get_string_size(int* w, int* h, const char* s, int s_len, int font_num);
void g_solid_render_ui();
void evaluate_restrict_disable_ss();
5 changes: 5 additions & 0 deletions game_patch/multi/multi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#include "../rf/entity.h"
#include "../rf/ai.h"
#include "../rf/item.h"
#include "../main/main.h"
#include "../graphics/gr.h"

// Note: this must be called from DLL init function
// Note: we can't use global variable because that would lead to crash when launcher loads this DLL to check dependencies
Expand Down Expand Up @@ -74,6 +76,9 @@ CodeInjection multi_start_injection{
[]() {
void debug_multi_init();
debug_multi_init();
if (g_game_config.try_lightmaps_only) {
evaluate_lightmaps_only();
}
},
};

Expand Down
3 changes: 3 additions & 0 deletions game_patch/multi/multi.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ struct DashFactionServerInfo
uint8_t version_minor = 0;
bool saving_enabled = false;
std::optional<float> max_fov;
bool allow_fb_mesh = false;
bool allow_lmap = false;
bool allow_no_ss = false;
};

void multi_level_download_update();
Expand Down
21 changes: 18 additions & 3 deletions game_patch/multi/network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -664,9 +664,12 @@ struct DashFactionJoinAcceptPacketExt
uint8_t version_minor = VERSION_MINOR;

enum class Flags : uint32_t {
none = 0,
saving_enabled = 1,
max_fov = 2,
none = 0,
saving_enabled = 1 << 0,
max_fov = 1 << 1,
allow_fb_mesh = 1 << 2,
allow_lmap = 1 << 3,
allow_no_ss = 1 << 4,
} flags = Flags::none;

float max_fov;
Expand Down Expand Up @@ -696,6 +699,15 @@ CallHook<int(const rf::NetAddr*, std::byte*, size_t)> send_join_accept_packet_ho
ext_data.flags |= DashFactionJoinAcceptPacketExt::Flags::max_fov;
ext_data.max_fov = server_get_df_config().max_fov.value();
}
if (server_allow_fullbright_meshes()) {
ext_data.flags |= DashFactionJoinAcceptPacketExt::Flags::allow_fb_mesh;
}
if (server_allow_lightmaps_only()) {
ext_data.flags |= DashFactionJoinAcceptPacketExt::Flags::allow_lmap;
}
if (server_allow_disable_screenshake()) {
ext_data.flags |= DashFactionJoinAcceptPacketExt::Flags::allow_no_ss;
}
auto [new_data, new_len] = extend_packet(data, len, ext_data);
return send_join_accept_packet_hook.call_target(addr, new_data.get(), new_len);
},
Expand All @@ -717,6 +729,9 @@ CodeInjection process_join_accept_injection{
xlog::debug("Got DF server info: {} {} {}", ext_data.version_major, ext_data.version_minor,
static_cast<int>(ext_data.flags));
server_info.saving_enabled = !!(ext_data.flags & DashFactionJoinAcceptPacketExt::Flags::saving_enabled);
server_info.allow_fb_mesh = !!(ext_data.flags & DashFactionJoinAcceptPacketExt::Flags::allow_fb_mesh);
server_info.allow_lmap = !!(ext_data.flags & DashFactionJoinAcceptPacketExt::Flags::allow_lmap);
server_info.allow_no_ss = !!(ext_data.flags & DashFactionJoinAcceptPacketExt::Flags::allow_no_ss);

constexpr float default_fov = 90.0f;
if (!!(ext_data.flags & DashFactionJoinAcceptPacketExt::Flags::max_fov) && ext_data.max_fov >= default_fov) {
Expand Down
27 changes: 27 additions & 0 deletions game_patch/multi/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,18 @@ void load_additional_server_config(rf::Parser& parser)
}
}

if (parser.parse_optional("$DF Allow Fullbright Meshes:")) {
g_additional_server_config.allow_fullbright_meshes = parser.parse_bool();
}

if (parser.parse_optional("$DF Allow Lightmaps Only Mode:")) {
g_additional_server_config.allow_lightmaps_only = parser.parse_bool();
}

if (parser.parse_optional("$DF Allow Disable Screenshake:")) {
g_additional_server_config.allow_disable_screenshake = parser.parse_bool();
}

if (parser.parse_optional("$DF Send Player Stats Message:")) {
g_additional_server_config.stats_message_enabled = parser.parse_bool();
}
Expand Down Expand Up @@ -754,6 +766,21 @@ bool server_is_saving_enabled()
return g_additional_server_config.saving_enabled;
}

bool server_allow_fullbright_meshes()
{
return g_additional_server_config.allow_fullbright_meshes;
}

bool server_allow_lightmaps_only()
{
return g_additional_server_config.allow_lightmaps_only;
}

bool server_allow_disable_screenshake()
{
return g_additional_server_config.allow_disable_screenshake;
}

bool server_weapon_items_give_full_ammo()
{
return g_additional_server_config.weapon_items_give_full_ammo;
Expand Down
3 changes: 3 additions & 0 deletions game_patch/multi/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ void server_init();
void server_do_frame();
bool check_server_chat_command(const char* msg, rf::Player* sender);
bool server_is_saving_enabled();
bool server_allow_fullbright_meshes();
bool server_allow_lightmaps_only();
bool server_allow_disable_screenshake();
void server_reliable_socket_ready(rf::Player* player);
bool server_weapon_items_give_full_ammo();
3 changes: 3 additions & 0 deletions game_patch/multi/server_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ struct ServerAdditionalConfig
bool upnp_enabled = true;
std::optional<int> force_player_character;
std::optional<float> max_fov;
bool allow_fullbright_meshes = false;
bool allow_lightmaps_only = false;
bool allow_disable_screenshake = false;
int anticheat_level = 0;
bool stats_message_enabled = true;
std::string welcome_message;
Expand Down
Loading