Вариантов много, в зависимости от качества соединения, приемлемости лагов и возможностей мошенничества.
Но нужно понимать что анимацию в таких играх на сервер не завязывают, игровой сервер отвечает за корректность изменения состояний игрового мира и может выдать текущее состояние игровых объектов.
В общем случае суть где то такая:
1) на сервер отсылается запрос "посадить_укроп_в_грядке_с_координатами(5,5)"
2) Сервер, запоминает состояние грядки в координате 5,5 и присылает ответ, что всё ок, расти будет 300 секунд.
3) Клиент запускает таймер на 300 секунд, по которому будет меняться анимация того как растёт укроп
4) По истечению 300 секунд клиент переводит укроп в координатах 5,5 в состояние "готов к уборке"
5) Пользователь жмёт собрать укроп, на сервер уходит "собирать_урожай_в_координатах(5,5)"
6) Сервер проверяет, что прошло достаточно времени (т.е. 300 секунд +/- лаги) и даёт ответ, что да можно собирать укроп. И сохраняет состояние грядки как пустая, а укроп перекидывает в амбар.
Так же стоит отметить, что секунда на сервере, ещё кое как, близка астрономической, но вот 1 секунда на JS в браузере может быть какой угодно.
Поэтому никто секунды не считает, считают дельту по времени.
Т.е. создают объект на который в котором запоминаются таймауты в секундах, текущее время и функции которые будут вызваны по их истечению. Потом setinterval/setTimeout допустим раз в 1 сотою секунды проверяет дельты текущего времени к сохранённым в этом объекте, и если дельта больше чем таймаут то дёргает функции обработчики.
Для начального варианта сетевого протокола достаточно просто отсылать HTTP запросы по событиям, по мере роста проекта будет понятно в какую сторону оптимизировать протокол т.к. вариаций тут реально много.