netplay work

This commit is contained in:
Eric Froemling 2021-03-19 17:18:37 -05:00
parent 205635d51f
commit 9192b4f50e
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
17 changed files with 250 additions and 130 deletions

View File

@ -3932,40 +3932,40 @@
"assets/build/windows/Win32/ucrtbased.dll": "https://files.ballistica.net/cache/ba1/b5/85/f8b6d0558ddb87267f34254b1450",
"assets/build/windows/Win32/vc_redist.x86.exe": "https://files.ballistica.net/cache/ba1/1c/e1/4a1a2eddda2f4aebd5f8b64ab08e",
"assets/build/windows/Win32/vcruntime140d.dll": "https://files.ballistica.net/cache/ba1/50/8d/bc2600ac9491f1b14d659709451f",
"build/prefab/full/linux_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d1/cd/67331a44c2d6f296bf77f33ee306",
"build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/eb/0e/9ce47318a17ce9ae48c91c2da8d0",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6c/e6/7446860570852b068f72af2fb9fe",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/85/61/ce38df8bbb8ea1472a9669e4b6d7",
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/61/83/1111ea2ea7fc3761acde2dc06292",
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/88/9c/931d1c5f404fc66a5e458bb2f428",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/dc/52/6ad3df68aeaa90e9a43093f5b4d9",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/6d/b8/1ecbd98f66ec260fcffeb64a9b37",
"build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/67/78/2af711de47c5239ef26017aa30c5",
"build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/13/94/db30b2bc3e2c1106a8fe83a079c6",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b5/88/4cf938c5876c74060ae87be8739f",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/fd/0e/c35f6920f03ef6b762948133b316",
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/47/08/9bf4c023631178c59ae1bd272ca4",
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/71/19/42f7719d481349cc1f5fe9a7d99d",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/f5/57/af559c12b01375b3fcaf33481655",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/5a/9d/870578d93d2b3b2c1bcc784f55e7",
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/f5/14/a1ccbdf25ba24d1d46bcde6ae015",
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/4a/ea/967d2fe1adab321afadc6144c56c",
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cb/d1/c43570bda2cbb6e6f8e767c054b9",
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/cc/15/803086f664162eb61aae4363ee76",
"build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4c/bf/393694ea67f3d590dd2706c9955e",
"build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/78/cb/bb9ae4f896f862074057c8e36e1d",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ae/bd/39d7b885f7f01e81d0e96f0f85ce",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/30/da/709e6b36f4f3158843d3a39032c6",
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c0/9b/5d60f10dbe2e6f670b9e177bce16",
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/52/d9/563a6949d2c4db5a915c54460fbc",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/d0/6a/42fe8d2e34f95e1b3282e8422344",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/50/cf/bad44b07a4022aee3001002086b5",
"build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/30/e6/1f20540e32ee690d548bbe78e038",
"build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/8f/e8/4153e97345a2405df151702b8fc9",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ef/d5/76b650d50e50a839fda4e499c270",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b3/3d/38218c0f9a876513c854ed75e960",
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7c/58/c16677ab8794b977e95671e007e1",
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/2e/e5/d6af87158a6209d96b5c0ef797c0",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c4/11/2082e99d03f4454f10dda7e56e6d",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/7f/0a/fe4b2c683075cf837b9f0c37fe87"
"build/prefab/full/linux_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/fd/41/a1ef000678c7cb89f87133a8f570",
"build/prefab/full/linux_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/f8/12/c69a75fae714824ad525e43876d9",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/13/c2/f88ae12e42b164cc7ca9ed61e230",
"build/prefab/full/linux_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/05/01/9aca815693cfc9200fe937a2ae58",
"build/prefab/full/linux_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/d6/20/7061a88a9dbd5c51eea45fce76bf",
"build/prefab/full/linux_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/90/cb/be6d4aa11eb87cef4716d7e31901",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/17/df/23215ac9d4dacaa44edfd2310b91",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/a7/ad/1ec53567ccbd6a83334516b1c29b",
"build/prefab/full/mac_arm64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/4c/f5/d4bb7ed9f5f8dd2e7a5efbdeb5fe",
"build/prefab/full/mac_arm64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/d9/9c/0e65f40739f4023f2fd5c7c4fdf2",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/ba/fd/ac27673e2a5d56edf1b01d88da67",
"build/prefab/full/mac_arm64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/39/4c/206eecc8816ba3d46c28030cb795",
"build/prefab/full/mac_x86_64/debug/ballisticacore": "https://files.ballistica.net/cache/ba1/b5/b5/7b5e887b9f0223f4372b97bd3e70",
"build/prefab/full/mac_x86_64/release/ballisticacore": "https://files.ballistica.net/cache/ba1/fd/c0/388a49b4a8b2879c6924fade2cc6",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/55/9e/e4a8a4458b7582883873d473fb42",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticacore_headless": "https://files.ballistica.net/cache/ba1/b3/c6/8c6ef646c2aa04e218b8f4974dc2",
"build/prefab/full/windows_x86/debug/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/65/73/6d3ed79e37a08f575df04145b43d",
"build/prefab/full/windows_x86/release/BallisticaCore.exe": "https://files.ballistica.net/cache/ba1/e9/03/60abb7a8cd8850fe4e1da24ff5ec",
"build/prefab/full/windows_x86_server/debug/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e2/76/0d2133bb2cbde40f684dc33e0720",
"build/prefab/full/windows_x86_server/release/dist/ballisticacore_headless.exe": "https://files.ballistica.net/cache/ba1/e0/0e/36917b6deb6a079b73da41af358d",
"build/prefab/lib/linux_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/11/a7/73334288aedb6a2f990ae204ada6",
"build/prefab/lib/linux_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/14/20/4225a2af6c3893b9ab8b6ebd3e23",
"build/prefab/lib/linux_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a9/62/6166bba0b039be543105d1d7b642",
"build/prefab/lib/linux_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/eb/93/9d28ef49f8848703dfc6b233f7c1",
"build/prefab/lib/linux_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/4c/51/0461da41b8cd8c02ff9260035e61",
"build/prefab/lib/linux_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ad/fa/7e4876b066d04ddef7d0cb60f44c",
"build/prefab/lib/linux_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/54/e3/ebd341c2c759ce067db1a740238b",
"build/prefab/lib/linux_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/ec/bf/eb162e4704b9d970537ffe210d8d",
"build/prefab/lib/mac_arm64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/aa/3a/a9ab538fb7754ae31870703fb253",
"build/prefab/lib/mac_arm64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/51/8b/0fed5e510cc87557a79814211a05",
"build/prefab/lib/mac_arm64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/c4/6c/5f22862278b52e6d1b63d1f28b94",
"build/prefab/lib/mac_arm64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/b5/1f/983902fc58ea15a69653678f53b0",
"build/prefab/lib/mac_x86_64/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/a0/90/0d1a8771ad1798153180a28e453b",
"build/prefab/lib/mac_x86_64/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/be/69/9072e5c66d0eb21727212843be8c",
"build/prefab/lib/mac_x86_64_server/debug/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/64/20/ee2ab6fee781ee8f1e2532c00dc2",
"build/prefab/lib/mac_x86_64_server/release/libballisticacore_internal.a": "https://files.ballistica.net/cache/ba1/22/1e/7178ea47b9331addd638c8e81b55"
}

View File

@ -871,6 +871,7 @@
<w>getcurrency</w>
<w>getcwd</w>
<w>getdata</w>
<w>gethostbyname</w>
<w>getinputdevice</w>
<w>getkillerplayer</w>
<w>getlevel</w>

View File

@ -1,4 +1,6 @@
### 1.6.0 (20308)
- Revamped netcode significantly. We still don't have client-prediction, but things should (hopefully) feel much lower latency now.
- Added network debug graphs accessible by hitting F8.
- Added private parties functionality (cloud hosted parties with associated codes making it easier to play with friends)
- The meta subsystem now enables new plugins by default in headless builds.
- Added option to save party in Manual tab

View File

@ -372,6 +372,7 @@
<w>getbitshigh</w>
<w>getcollidemodel</w>
<w>getdata</w>
<w>gethostbyname</w>
<w>getifaddrs</w>
<w>getinputdevice</w>
<w>getline</w>

View File

@ -1,5 +1,5 @@
<!-- THIS FILE IS AUTO GENERATED; DO NOT EDIT BY HAND -->
<h4><em>last updated on 2021-03-11 for Ballistica version 1.6.0 build 20323</em></h4>
<h4><em>last updated on 2021-03-19 for Ballistica version 1.6.0 build 20324</em></h4>
<p>This page documents the Python classes and functions in the 'ba' module,
which are the ones most relevant to modding in Ballistica. If you come across something you feel should be included here or could be better explained, please <a href="mailto:support@froemling.net">let me know</a>. Happy modding!</p>
<hr>

View File

@ -66,14 +66,15 @@ class AppGlobals {
std::string user_config_dir;
bool started_suicide{};
// Netplay testing.
int buffer_time{1000 / 30};
// Maximum time in milliseconds to buffer game input/output before sending
// it over the network.
int buffer_time{0};
// How often we send dynamics sync packets.
// How often we send dynamics resync messages.
int dynamics_sync_time{500};
// How many steps we sample for each bucket.
int delay_samples{20};
int delay_bucket_samples{60};
bool vr_mode{g_buildconfig.vr_build()};
// Temp dirty way to do some shutdown stuff (FIXME: move to an App method).

View File

@ -21,7 +21,7 @@
namespace ballistica {
// These are set automatically via script; don't change here.
const int kAppBuildNumber = 20323;
const int kAppBuildNumber = 20325;
const char* kAppVersion = "1.6.0";
// Our standalone globals.

View File

@ -1117,7 +1117,7 @@ void Game::PushToggleManualCameraCall() {
}
void Game::PushToggleDebugInfoDisplayCall() {
PushCall([] { g_graphics->ToggleDebugInfoDisplay(); });
PushCall([] { g_graphics->ToggleNetworkDebugDisplay(); });
}
void Game::PushToggleCollisionGeometryDisplayCall() {

View File

@ -21,20 +21,22 @@ class ClientSession : public Session {
virtual auto GetActualTimeAdvance(int advance_in) -> int {
return advance_in;
}
void Update(int time_advance) override;
void Draw(FrameDef* f) override;
virtual void HandleSessionMessage(const std::vector<uint8_t>& buffer);
void Reset(bool rewind);
auto Update(int time_advance) -> void override;
auto Draw(FrameDef* f) -> void override;
virtual auto HandleSessionMessage(const std::vector<uint8_t>& buffer) -> void;
auto Reset(bool rewind) -> void;
auto GetForegroundContext() -> Context override;
auto DoesFillScreen() const -> bool override;
void ScreenSizeChanged() override;
void LanguageChanged() override;
auto shutting_down() const -> bool { return shutting_down_; }
void GetCorrectionMessages(bool blend,
std::vector<std::vector<uint8_t> >* messages);
auto ScreenSizeChanged() -> void override;
auto LanguageChanged() -> void override;
auto GetCorrectionMessages(bool blend,
std::vector<std::vector<uint8_t> >* messages)
-> void;
// Called when attempting to step without input data available.
virtual void OnCommandBufferUnderrun() {}
/// Called when attempting to step without input data available.
virtual auto OnCommandBufferUnderrun() -> void {}
virtual auto OnBaseTimeStepAdded(int step) -> void {}
// Returns existing objects; throws exceptions if not available.
auto GetScene(int id) const -> Scene*;
@ -45,46 +47,83 @@ class ClientSession : public Session {
auto GetMaterial(int id) const -> Material*;
auto GetSound(int id) const -> Sound*;
protected:
virtual void OnReset(bool rewind);
virtual void FetchMessages() {}
int steps_on_list_;
std::list<std::vector<uint8_t> > commands_; // ready-to-go commands
auto base_time_buffered() const { return base_time_buffered_; }
auto consume_rate() const { return consume_rate_; }
auto set_consume_rate(float val) { consume_rate_ = val; }
auto target_base_time() const { return target_base_time_; }
auto base_time() const { return base_time_; }
auto shutting_down() const { return shutting_down_; }
auto scenes() const -> const std::vector<Object::Ref<Scene> >& {
return scenes_;
}
auto nodes() const -> const std::vector<Object::WeakRef<Node> >& {
return nodes_;
}
auto textures() const -> const std::vector<Object::Ref<Texture> >& {
return textures_;
}
auto models() const -> const std::vector<Object::Ref<Model> >& {
return models_;
}
auto sounds() const -> const std::vector<Object::Ref<Sound> >& {
return sounds_;
}
auto collide_models() const
-> const std::vector<Object::Ref<CollideModel> >& {
return collide_models_;
}
auto materials() const -> const std::vector<Object::Ref<Material> >& {
return materials_;
}
auto commands() const -> const std::list<std::vector<uint8_t> >& {
return commands_;
}
auto add_end_of_file_command() {
commands_.emplace_back(1, static_cast<uint8_t>(SessionCommand::kEndOfFile));
}
virtual auto OnReset(bool rewind) -> void;
virtual auto FetchMessages() -> void {}
virtual void Error(const std::string& description);
void End();
millisecs_t base_time_;
double target_base_time_ = 0.0f;
bool shutting_down_;
std::vector<int> least_buffered_count_list_; // move this to net-client?..
std::vector<int> most_buffered_count_list_;
int buffer_count_list_index_;
int adjust_counter_;
float correction_ = 1.0f;
float largest_spike_smoothed_ = 0.0f;
float low_pass_smoothed_ = 0.0f;
void DumpFullState(GameStream* out) override;
/// Reset target base time to equal current. This can be used during command
/// buffer underruns to cause playback to pause momentarily instead of
/// skipping ahead to catch up. Generally desired for replays but not for
/// net-play.
auto ResetTargetBaseTime() -> void { target_base_time_ = base_time_; }
private:
void ClearSessionObjs();
void AddCommand(const std::vector<uint8_t>& command);
// commands being built up for the next time step
// (we want to be able to run *everything* for a given timestep at once
// to avoid drawing things in half-changed states, etc)
std::list<std::vector<uint8_t> > commands_pending_; // commands for the next
std::vector<uint8_t> current_cmd_;
uint8_t* current_cmd_ptr_;
auto ReadByte() -> uint8_t;
auto ReadInt32() -> int32_t;
void ReadInt32_2(int32_t* vals);
void ReadInt32_3(int32_t* vals);
void ReadInt32_4(int32_t* vals);
auto ReadInt32_2(int32_t* vals) -> void;
auto ReadInt32_3(int32_t* vals) -> void;
auto ReadInt32_4(int32_t* vals) -> void;
auto ReadString() -> std::string;
auto ReadFloat() -> float;
void ReadFloats(int count, float* vals);
void ReadInt32s(int count, int32_t* vals);
void ReadChars(int count, char* vals);
auto ReadFloats(int count, float* vals) -> void;
auto ReadInt32s(int count, int32_t* vals) -> void;
auto ReadChars(int count, char* vals) -> void;
// Ready-to-go commands.
std::list<std::vector<uint8_t> > commands_;
// Commands being built up for the next time step (we need to ship timesteps
// as a whole).
std::list<std::vector<uint8_t> > commands_pending_;
std::vector<uint8_t> current_cmd_;
uint8_t* current_cmd_ptr_{};
int base_time_buffered_{};
bool shutting_down_{};
millisecs_t base_time_{};
double target_base_time_{};
float consume_rate_{1.0f};
protected:
std::vector<Object::Ref<Scene> > scenes_;
std::vector<Object::WeakRef<Node> > nodes_;
std::vector<Object::Ref<Texture> > textures_;

View File

@ -17,17 +17,44 @@ class NetClientSession : public ClientSession {
auto connection_to_host() const -> ConnectionToHost* {
return connection_to_host_.get();
}
void SetConnectionToHost(ConnectionToHost* c);
void HandleSessionMessage(const std::vector<uint8_t>& buffer) override;
void OnCommandBufferUnderrun() override;
protected:
void Update(int time_advance) override;
auto SetConnectionToHost(ConnectionToHost* c) -> void;
auto HandleSessionMessage(const std::vector<uint8_t>& buffer)
-> void override;
auto OnCommandBufferUnderrun() -> void override;
auto Update(int time_advance) -> void override;
auto OnReset(bool rewind) -> void override;
auto OnBaseTimeStepAdded(int step) -> void override;
private:
void UpdateBuffering();
bool writing_replay_ = false;
struct SampleBucket {
// int least_buffered_count{};
// int most_buffered_count{};
int max_delay_from_projection{};
};
auto ProjectedBaseTime(millisecs_t now) const -> millisecs_t {
return leading_base_time_received_
+ (now - leading_base_time_receive_time_);
}
auto UpdateBuffering() -> void;
auto GetBucketNum() -> int;
bool writing_replay_{};
millisecs_t base_time_received_{};
millisecs_t last_base_time_receive_time_{};
millisecs_t leading_base_time_received_{};
millisecs_t leading_base_time_receive_time_{};
Object::WeakRef<ConnectionToHost> connection_to_host_;
std::vector<SampleBucket> buckets_{5};
// float bucket_max_smoothed_{};
// float bucket_min_smoothed_{};
float max_delay_smoothed_{};
float last_bucket_max_delay_{};
float current_delay_{};
int delay_sample_counter_{};
int adjust_counter_{};
};
} // namespace ballistica

View File

@ -17,25 +17,24 @@ class ReplayClientSession : public ClientSession,
public:
explicit ReplayClientSession(std::string filename);
~ReplayClientSession() override;
void OnReset(bool rewind) override;
auto OnReset(bool rewind) -> void override;
// Our ClientControllerInterface implementation.
auto GetActualTimeAdvance(int advance_in) -> int override;
void OnClientConnected(ConnectionToClient* c) override;
void OnClientDisconnected(ConnectionToClient* c) override;
void DumpFullState(GameStream* out) override;
auto OnClientConnected(ConnectionToClient* c) -> void override;
auto OnClientDisconnected(ConnectionToClient* c) -> void override;
auto OnCommandBufferUnderrun() -> void override;
protected:
void Error(const std::string& description) override;
void FetchMessages() override;
auto Error(const std::string& description) -> void override;
auto FetchMessages() -> void override;
private:
uint32_t message_fetch_num_;
bool have_sent_client_message_;
uint32_t message_fetch_num_{};
bool have_sent_client_message_{};
std::vector<ConnectionToClient*> connections_to_clients_;
std::vector<ConnectionToClient*> connections_to_clients_ignored_;
std::string file_name_;
FILE* file_;
FILE* file_{};
};
} // namespace ballistica

View File

@ -386,16 +386,22 @@ void Graphics::DrawMiscOverlays(RenderPass* pass) {
}
}
// Draw debug graphs.
if (explicit_bool(false)) {
if (!debug_graph_1_.exists()) {
debug_graph_1_ = Object::New<NetGraph>();
// Draw any debug graphs.
{
float debug_graph_y = 50.0;
auto now = GetRealTime();
for (auto it = debug_graphs_.begin(); it != debug_graphs_.end();) {
assert(it->second.exists());
if (now - it->second->LastUsedTime() > 1000) {
it = debug_graphs_.erase(it);
} else {
it->second->Draw(pass, GetRealTime(), 50.0f, debug_graph_y, 500.0f,
100.0f);
debug_graph_y += 110.0f;
++it;
}
}
debug_graph_1_->Draw(pass, GetRealTime(), 50.0f, 50.0f, 500.0f, 100.0f);
if (!debug_graph_2_.exists()) {
debug_graph_2_ = Object::New<NetGraph>();
}
debug_graph_2_->Draw(pass, GetRealTime(), 50.0f, 160.0f, 500.0f, 100.0f);
}
// Screen messages (bottom).
@ -736,6 +742,18 @@ void Graphics::DrawMiscOverlays(RenderPass* pass) {
}
}
auto Graphics::GetDebugGraph(const std::string& name, bool smoothed)
-> NetGraph* {
auto out = debug_graphs_.find(name);
if (out == debug_graphs_.end()) {
debug_graphs_[name] = Object::New<NetGraph>();
debug_graphs_[name]->SetLabel(name);
debug_graphs_[name]->SetSmoothed(smoothed);
}
debug_graphs_[name]->SetLastUsedTime(GetRealTime());
return debug_graphs_[name].get();
}
void Graphics::GetSafeColor(float* red, float* green, float* blue,
float target_intensity) {
assert(red && green && blue);
@ -1462,13 +1480,13 @@ void Graphics::LocalCameraShake(float mag) {
}
}
void Graphics::ToggleDebugInfoDisplay() {
void Graphics::ToggleNetworkDebugDisplay() {
assert(InGameThread());
debug_info_display_ = !debug_info_display_;
if (debug_info_display_) {
ScreenMessage("debug info on\n");
network_debug_display_enabled_ = !network_debug_display_enabled_;
if (network_debug_display_enabled_) {
ScreenMessage("Network Debug Display Enabled");
} else {
ScreenMessage("debug info off\n");
ScreenMessage("Network Debug Display Disabled");
}
}

View File

@ -129,8 +129,10 @@ class Graphics {
auto ToggleManualCamera() -> void;
auto LocalCameraShake(float intensity) -> void;
auto ToggleDebugDraw() -> void;
auto debug_info_display() const -> bool { return debug_info_display_; }
auto ToggleDebugInfoDisplay() -> void;
auto network_debug_info_display_enabled() const -> bool {
return network_debug_display_enabled_;
}
auto ToggleNetworkDebugDisplay() -> void;
auto SetGyroEnabled(bool enable) -> void;
auto floor_reflection() const -> bool {
assert(InGameThread());
@ -265,8 +267,7 @@ class Graphics {
auto set_gyro_vals(const Vector3f& vals) -> void { gyro_vals_ = vals; }
auto show_net_info() const -> bool { return show_net_info_; }
auto set_show_net_info(bool val) -> void { show_net_info_ = val; }
auto debug_graph_1() const -> NetGraph* { return debug_graph_1_.get(); }
auto debug_graph_2() const -> NetGraph* { return debug_graph_2_.get(); }
auto GetDebugGraph(const std::string& name, bool smoothed) -> NetGraph*;
// Used by meshes.
auto AddMeshDataCreate(MeshData* d) -> void;
@ -372,12 +373,11 @@ class Graphics {
bool show_net_info_{};
bool tv_border_{};
bool floor_reflection_{};
Object::Ref<NetGraph> debug_graph_1_;
Object::Ref<NetGraph> debug_graph_2_;
std::map<std::string, Object::Ref<NetGraph> > debug_graphs_;
std::mutex frame_def_delete_list_mutex_;
std::vector<FrameDef*> frame_def_delete_list_;
bool debug_draw_{};
bool debug_info_display_{};
bool network_debug_display_enabled_{};
Object::Ref<Camera> camera_;
millisecs_t next_stat_update_time_{};
int last_total_frames_rendered_{};

View File

@ -14,16 +14,30 @@ class NetGraph::Impl {
std::list<std::pair<double, float>> samples;
double duration = 2000.0;
double v_max_smoothed = 1.0;
double v_smoothed = 0.0;
bool smoothed = false;
std::string label;
ImageMesh bg_mesh;
MeshIndexedSimpleFull value_mesh;
TextGroup max_vel_text;
millisecs_t last_used_time{};
};
NetGraph::NetGraph() : impl_(new NetGraph::Impl()) {}
NetGraph::~NetGraph() = default;
void NetGraph::AddSample(double time, double value) {
auto NetGraph::SetLabel(const std::string& label) -> void {
impl_->label = label;
}
auto NetGraph::SetSmoothed(bool val) -> void { impl_->smoothed = val; }
auto NetGraph::SetLastUsedTime(millisecs_t real_time) -> void {
impl_->last_used_time = real_time;
}
auto NetGraph::LastUsedTime() -> millisecs_t { return impl_->last_used_time; }
auto NetGraph::AddSample(double time, double value) -> void {
impl_->samples.emplace_back(time, value);
double cutoffTime = time - impl_->duration;
@ -49,6 +63,8 @@ void NetGraph::Draw(RenderPass* pass, double time, double x, double y, double w,
int num_samples = static_cast<int>(impl_->samples.size());
double val = 0.0;
// Draw values (provided we have at least 2 samples)
bool draw_values = (num_samples >= 2);
if (draw_values) {
@ -66,8 +82,10 @@ void NetGraph::Draw(RenderPass* pass, double time, double x, double y, double w,
}
}
double smoothing = 0.95;
val = impl_->samples.back().second;
impl_->v_max_smoothed =
smoothing * impl_->v_max_smoothed + (1.0 - smoothing) * v_max * 1.1;
impl_->v_smoothed = smoothing * impl_->v_smoothed + (1.0 - smoothing) * val;
double v_top = impl_->v_max_smoothed;
double v_height = v_top - v_bottom;
@ -129,7 +147,14 @@ void NetGraph::Draw(RenderPass* pass, double time, double x, double y, double w,
c.Submit();
char val_str[32];
snprintf(val_str, sizeof(val_str), "%.2f", impl_->v_max_smoothed);
if (!impl_->label.empty()) {
snprintf(val_str, sizeof(val_str), "%s %.3f", impl_->label.c_str(),
impl_->smoothed ? impl_->v_smoothed : val);
} else {
snprintf(val_str, sizeof(val_str), "%.3f",
impl_->smoothed ? impl_->v_smoothed : val);
}
impl_->max_vel_text.SetText(val_str, TextMesh::HAlign::kLeft,
TextMesh::VAlign::kTop);

View File

@ -4,6 +4,7 @@
#define BALLISTICA_GRAPHICS_NET_GRAPH_H_
#include <memory>
#include <string>
#include "ballistica/core/object.h"
@ -13,9 +14,13 @@ class NetGraph : public Object {
public:
NetGraph();
~NetGraph() override;
void AddSample(double time, double value);
void Draw(RenderPass* pass, double time, double x, double y, double w,
double h);
auto AddSample(double time, double value) -> void;
auto SetLabel(const std::string& label) -> void;
auto SetLastUsedTime(millisecs_t real_time) -> void;
auto LastUsedTime() -> millisecs_t;
auto SetSmoothed(bool smoothed) -> void;
auto Draw(RenderPass* pass, double time, double x, double y, double w,
double h) -> void;
private:
class Impl;

View File

@ -248,10 +248,11 @@ void InputDevice::ShipBufferIfFull() {
// Ship the buffer once it gets big enough or once enough time has passed.
millisecs_t real_time = GetRealTime();
size_t size = remote_input_commands_buffer_.size();
if (size > 2
&& (static_cast<int>(real_time - last_remote_input_commands_send_time_)
> g_app_globals->buffer_time
>= g_app_globals->buffer_time
|| size > 400)) {
last_remote_input_commands_send_time_ = real_time;
hc->SendReliableMessage(remote_input_commands_buffer_);

View File

@ -281,13 +281,14 @@ auto PyValueTest(PyObject* self, PyObject* args, PyObject* keywds)
return_val = g_app_globals->buffer_time;
} else if (!strcmp(arg, "delaySampling")) {
if (have_change) {
g_app_globals->delay_samples += static_cast<int>(change);
g_app_globals->delay_bucket_samples += static_cast<int>(change);
}
if (have_absolute) {
g_app_globals->buffer_time = static_cast<int>(absolute);
}
g_app_globals->delay_samples = std::max(1, g_app_globals->delay_samples);
return_val = g_app_globals->delay_samples;
g_app_globals->delay_bucket_samples =
std::max(1, g_app_globals->delay_bucket_samples);
return_val = g_app_globals->delay_bucket_samples;
} else if (!strcmp(arg, "dynamicsSyncTime")) {
if (have_change) {
g_app_globals->dynamics_sync_time += static_cast<int>(change);