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

Design core gamestate #964

Closed
TheJJ opened this issue Jan 25, 2018 · 4 comments
Closed

Design core gamestate #964

TheJJ opened this issue Jan 25, 2018 · 4 comments
Labels
area: simulation Involved in the game mechanics and simulation lang: c++ Done in C++ code to-discuss Idea or suggestion that needs some discussion before implementation

Comments

@TheJJ
Copy link
Member

TheJJ commented Jan 25, 2018

We have to come up with a simple gamestate definition for the event logic.

It could, for example, consist of

  • Game (main state container)
  • Universe (currently running game world)
  • GameEntity (base simulation element)
  • Player (guess what)

The combination and configuration of those is done by nyan. The logic implementation and available features for GameEntities are in C++ and Python.

This is the foundation for the new simulation core.

It should also be prepared to support pathfinding (with an obstruction manager or something suitable #736).

@TheJJ TheJJ added lang: c++ Done in C++ code area: simulation Involved in the game mechanics and simulation to-discuss Idea or suggestion that needs some discussion before implementation labels Jan 25, 2018
@TheJJ TheJJ added this to To Do in simulation core Jan 25, 2018
@TheJJ
Copy link
Member Author

TheJJ commented Jan 25, 2018

@TheJJ TheJJ mentioned this issue Mar 16, 2018
@Tomatower
Copy link
Contributor

Tomatower commented Mar 16, 2018

Draft Paste:

namespace openage::gamestate {

using unit_id_t = uint64_t;
using property_id_t = uint64_t;
using player_id_t = uint64_t;

class NyanObserver : curve::EventTarget {
public:
	NyanObserver(const EventManager &mgr, const nyan::Object &object) :
		EventTarget(mgr) {
		object.onchange([this](const curve::curve_time_t &at) {
			this->onchange(at);
		});
	}
};

struct NyanIdentifier {
	nyan::fqon_t fqon;
	nyan::memberid_t member;
};


class Player {
public:
	nyan::Object civilisation;
	std::unordered_map<unit_id_t, std::weak_ptr> units;
};


class Ability {
public:
	Ability(const nyan::Object &);
	nyan::Object type;
};

class Property : curve::EventTarget {
public:
	Property(const EventManager *mgr) :
		EventTarget(mgr) {};
};

/**
 * Element in the game universe.
 *
 * Everything that is somehow relevant in the game is a Unit.
 */
class Entity : curve::EventTarget {
public:
	Entity(unit_id_t, const nyan::Object &);

	// Has to be kept in sync with the player list
	curve::Discrete<player_id_t> owning_player;

	/** The least common denominator is the position of an object. */
	std::shared_ptr<curve::Continuous<util::Vector<3>>> position;

	/**
	 * List of per-unit variables that are constructed from abilities and
	 * properties from nyan
	 */
	curve::unordered_map<property_id_t, std::shared_ptr<Property>> properties;

	/**
	 * property tracking within the nyan tree
	 *
	 * properties watched by this unit in nyan. This is used to traverse the
	 * on-change events from nyan into the event library.
	 */
	std::unordered_map<NyanIdentifier, std::shared_ptr<NyanObserver>> observed;

	/**
	 * The referenced unit type
	 */
	nyan::Object type;

	/**
	 * The unique identifier of this object.
	 */
	unit_id_t id;
};

class Universe {
public:
	Universe(const nyan::Object &);
	nyan::Object data;

	curve::unordered_map<unit_id_t, Unit> units;

	unit_id_t next_unit_id;
};

class Game {
public:
	Universe universe;
	EventManager evntmgr;
	std::unordered_map<player_id_t, Player> players;
};

}

@TheJJ TheJJ moved this from To Do to In progress in simulation core May 2, 2018
@TheJJ TheJJ added this to events in game logic May 2, 2018
@TheJJ TheJJ moved this from events to todo in game logic May 2, 2018
@simonsan simonsan added this to the Event-driven game logic milestone Sep 6, 2019
@simonsan
Copy link
Contributor

Informative comment of Tomatower

Reminder: "curves" are basically lines drawn between (time1, value1) and (time2, value2), with the option to calculate time1 <= time <= time2 as ((time2-time1)/(time-time1)* (value2 - value1)) + value1 - in other words: linear interpolation between two points identified by their time.

My suggestion, running on top of the curve-concept is the following:

The simulation keeps its own state, having all the curves, having all events, having all segments of path-planning.

The renderer also keeps its own state, having only the curves containing the two keyframes relevant for rendering at the moment. (and maybe the future - two keyframes may be as far apart as seconds, maybe even minutes!)

The simulation changes its state by executing at a lower rate than the presenter, keeping track of the changes it performed. The simulation needs for that a current "now", where changes must not happen before.
After it is done executing for a "physics-frame" it will apply all changes that happened to the keyframes that are currently in the presenter-state:

  1. By changing the second keyframe (for example the time of arrival of a unit, or the destination of a unit)
  2. By inserting the next keyframe into the buffer (because the time has passed by the second keyframe, and cannot continue rendering since it needs 2 for interpolation)

Inputs/Actions shall be stored in an action queue where the simulation picks it up and executes them at the appropriate times in the simulation. The simulation logic is currently build as an event-driven system, so user interactions can be implemented as "just another" event that happens within the game logic. And that way it would not matter for the logic if the event came from a keyboard or from a network input.

As actual code between the presenter and the simulation i think we have multiple options. One is to re-use the gamestate used in the simulation, so we do not have to duplicate the code, and just change the mode of operation for the containing types, the second would be to create a optimized subset, containing only the information that is relevant for the user interface rendering - but here it depends mostly on what the presenter needs to perform best.

@heinezen
Copy link
Member

heinezen commented Sep 8, 2023

Resolved by #1515 (implementation) and #1525 (architecture)

@heinezen heinezen closed this as completed Sep 8, 2023
simulation core automation moved this from In progress to Done Sep 8, 2023
game logic automation moved this from todo to done Sep 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: simulation Involved in the game mechanics and simulation lang: c++ Done in C++ code to-discuss Idea or suggestion that needs some discussion before implementation
Projects
game logic
  
done
Development

No branches or pull requests

4 participants