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

Only send changed object properties #15671

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

cx384
Copy link
Contributor

@cx384 cx384 commented Jan 11, 2025

Solves #14418

It's optimized for packet size and not for parsing performance. It could be improved, e.g. by counting leading zeros of the bitset, but I don't know if this would make sense, and it would probably have to use gotos.

This PR adds an update properties packet, which only contains changed properties, and a bit field to indicate which properties changed. (It does not add separate packets for every property and concatenate them, since the bit field solution should be more efficient in most cases, I guess.)

To do

This PR is a Work in Progress

How to test

TODO

Copy link
Contributor

@appgurueu appgurueu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder whether we can deduplicate this. Otherwise adding a single object property now requires changing code in what, 10+ places? 1

I feel that certainly something should be possible with macros. For example:

int i = 0;
#define CHANGED(X) change[i++] = X != other.X;
CHANGED(textures);
CHANGED(colors);
...

(frankly it's really frustrating that C++ offers no proper reflection here)

Similarly, with the right template function write, serialization could be:

int i = 0;
#define SERIALIZE(X) if (fields[i++]) write(os, X);
SERIALIZE(textures);
SERIALIZE(colors);
...

and conversely deserialization:

int i = 0;
#define DESERIALIZE(X) if (fields[i++]) X = read(os);
DESERIALIZE(textures);
DESERIALIZE(colors);
...

all three have the enumeration of properties in common, so we can even further deduplicate this, say using a macro, parameter packs and C++ 17 folding over parameter packs. demo:

#include <iostream>

void print(const int &i) { std::cout << i << std::endl; }
void print(const float &f) { std::cout << f << std::endl; }

void unprint(int &i) { std::cin >> i; }
void unprint(float &i) { std::cin >> i; }

struct Props {
	int i = 0;
	float f = 0;
#define MEMBERS i, f
	void write() const { writeArgs(MEMBERS); }
	void read() { readArgs(MEMBERS); }
#undef MEMBERS
private:
	template <class ... Ts>
	void writeArgs(const Ts & ... inputs) const
	{
		([&]{ print(inputs); }(), ...);
	}

	template <class ... Ts>
	void readArgs(Ts & ... inputs) const
	{
		([&]{ unprint(inputs); }(), ...);
	}
};

int main() {
	Props p;
	p.read();
	p.write();
}

(alternatively we could use variadic macros)


I also don't think it's worth bothering with sending only changed boolean "packs" (bytes).

Just pack them all up in a bitset which is always sent and call it a day. (Currently that would only need a measly 2 bytes, and 4 bytes are probably enough for the foreseeable future.)

Footnotes

  1. Most of this problem already existed before this PR, but this PR adds 3 more places in its current state (getChange, serializeChanges, deSerializeChanges), and I think we can do better than that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants