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

ServerGameState + SharedGameState Redesign Initial Implementation #45

Merged
merged 15 commits into from
Apr 24, 2024

Conversation

gilkeidar
Copy link
Contributor

Initial implementation of the ServerGameState + SharedGameState redesign.

The key idea here is that the server maintains an instance of the ServerGameState class which maintains all abstract game state data and logic, and after handling input events and updating the ServerGameState, the server generates an instance of the SharedGameState which contains all abstract game state data required by the client. SharedGameState is serializable and is what is sent to the client with LoadGameStateEvents.

Closes #42.

…e Debugger can only be used to debug a ServerGameState instance), and updated serialization test code to use ServerGameState and SharedGameState.
@gilkeidar gilkeidar added enhancement New feature or request MVP Minimal Viable Product!!! Must have Gameplay i love gameeing labels Apr 22, 2024
@gilkeidar gilkeidar self-assigned this Apr 22, 2024
// single template class - otherwise, each type-specific object vector will
// come with an extra free list and this will get hairy to use.

SmartVector<Object *> objects;
Copy link
Contributor

@atar13 atar13 Apr 23, 2024

Choose a reason for hiding this comment

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

I like this approach but I wanted to clarify the need for the SmartVectorclass. Is it to hide the implementation details of managing the freelist in SmartVector?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, exactly - currently, each object has two IDs, a global ID and a type-specific ID; the idea here is that the ServerGameState class would have vectors for each object type (e.g., Player, Creature, etc.) and objects of that type would be stored in these vectors. The type-specific ID of the object would be its index in this type-specific vector, and its global ID would be its index in a global vector<Object &> objects vector. To avoid wasting space, when objects get removed and then new objects get created, I'd like for the freed object IDs to get reassigned. This means that every vector will need a free list to keep track of available IDs, and since we may have as many of these vectors as there will be object types, I think it makes sense to encapsulate the vectors with their free lists in a new class, which here is SmartVector.

* @return ShareGameState instance that represents this ServerGameState
* instance.
*/
SharedGameState generateSharedGameState();
Copy link
Contributor

Choose a reason for hiding this comment

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

I like this approach of generating the SharedGameState from the version the server has.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not a huge fan of leaving many lines or entire files commented out. It's not that big of a deal but we do have Git tracking all our changes in case we want to revert to a previous version.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right, I will remove the old GameState files (so gamestate.cpp and gamestate.hpp).

Comment on lines 42 to 53
Object** ptrToPtr = this->objects.get(i);

if (ptrToPtr == nullptr) {
// Push empty object to SharedObject SmartVector
shared.objects.pushEmpty();
}
else {
Object* object = *ptrToPtr;

// Create a SharedObject from this object
shared.objects.push(object->generateSharedObject());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Handling the double pointer to an object here feels kinda clunky.

Maybe we can have SmartVector::get return a std::shared_ptr to the underlying Object (this would mean that we'd have a SmartVector of Object not Object*).

Also, this isn't that big of a deal and it's totally fine if we keep this.

Copy link
Contributor

@Tyler-Lentz Tyler-Lentz left a comment

Choose a reason for hiding this comment

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

Overall I think this is a solid foundation that summarizes all of the ideas that we have. I just have a couple of high level comments:

  1. Like Anthony said I think it would be best to get rid of all of the commented out code so that it's easier to parse and there is less noise.

  2. In addition, I think it would be better if whoever is iterating through a SmartVector doesn't have to worry about checking if the Objects they are retrieving are nullptr. That seems like it might get annoying to do, and I feel like someone could forget. To solve this, I think we could define a custom iterator for SmartVector that automatically skips over nullptr objects. I found this article talking about how to define custom iterators. I think this would be good to do anyways because it would be nice to get the good foreach syntax wherever we use a SmartVector. My idea would be to define an iterator on SmartVector whose ++ operation will keep iterating until it finds a valid object, and whose begin() makes sure to find the first object in the vector that is valid.

  3. Also, I think we can get around the restrictions of the vector resizing by making the vectors contain smart pointers so that we don't have to worry about their addresses changing, and we can safely return smart pointers to the underlying objects. I think this might be worth looking into later on. However, I think the SmartVector class would still be important because it abstracts away the free list logic.

I think it would be best to do 1. before merging in, but I think we can do 2. and 3. later on. Approving because 1 is a nitpick, and this is a good change and the sooner we merge in the better.

Also I think there might be some merge conflicts that have to be resolved before merging.

And also, I am a little bit worried about the amount of repeated data between the shared data structures and server data structures. I hope it doesn't end up being too much. If it does there might be a better way to represent that relationship. One idea might be to make the server side data structures just contain the shared data structures inside of them as data members so there isn't repeated definitions of the same values that have to be explicitly copied over.

@Tyler-Lentz Tyler-Lentz merged commit 68494f9 into dev Apr 24, 2024
11 checks passed
@Tyler-Lentz Tyler-Lentz deleted the refactor/ServerGameState branch April 24, 2024 21:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Gameplay i love gameeing Must have MVP Minimal Viable Product!!!
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants