Only save room contents if something changed

This commit is contained in:
kinther 2025-09-07 08:47:57 -07:00
parent 9d54d7d1a6
commit 7fafc7f6ea
5 changed files with 74 additions and 9 deletions

View file

@ -137,12 +137,12 @@ ACMD(do_save)
{
char a1[MAX_INPUT_LENGTH], a2[MAX_INPUT_LENGTH];
/* Parse up to two words so we can accept "save room" or "room save". */
/* Accept both orders: "save room" or "room save" */
two_arguments(argument, a1, a2);
/* Does either token equal "room"? (order-agnostic) */
const bool wants_room = ((*a1 && !str_cmp(a1, "room")) ||
(*a2 && !str_cmp(a2, "room")));
/* order-agnostic check */
int wants_room = ((*a1 && !str_cmp(a1, "room")) ||
(*a2 && !str_cmp(a2, "room")));
if (wants_room) {
room_rnum rnum = IN_ROOM(ch);
@ -163,8 +163,20 @@ ACMD(do_save)
/* Room is flagged SAVE → persist its contents */
if (RoomSave_now(rnum)) {
send_to_char(ch, "Saving room.\r\n");
mudlog(NRM, LVL_IMMORT, FALSE,
"RoomSave: manual save of room %d by %s.",
world[rnum].number, GET_NAME(ch));
/* If you added a dirty-save API and want to clear the bit on manual save,
you can optionally call it here (guard with a macro if desired):
#ifdef ROOMSAVE_HAVE_DIRTY_API
RoomSave_clear_dirty(rnum);
#endif
*/
} else {
send_to_char(ch, "Room save failed; see logs.\r\n");
mudlog(NRM, LVL_IMMORT, TRUE,
"SYSERR: RoomSave: manual save FAILED for room %d by %s.",
world[rnum].number, GET_NAME(ch));
}
return;
}

View file

@ -784,7 +784,8 @@ void boot_db(void)
}
/* Restore persistent room contents last so they take precedence. */
log("Loading Room Contents.");
log("Loading Room Contents.");
RoomSave_init_dirty();
RoomSave_boot();
log("Cleaning up last log.");

View file

@ -24,6 +24,7 @@
#include "fight.h"
#include "quest.h"
#include "mud_event.h"
#include "roomsave.h"
/* local file scope variables */
static int extractions_pending = 0;
@ -419,11 +420,15 @@ void char_to_room(struct char_data *ch, room_rnum room)
/* Give an object to a char. */
void obj_to_char(struct obj_data *object, struct char_data *ch)
{
room_rnum __rs_room = RoomSave_room_of_obj(object); /* where the item currently lives */
if (object && ch) {
object->next_content = ch->carrying;
ch->carrying = object;
object->carried_by = ch;
IN_ROOM(object) = NOWHERE;
if (__rs_room != NOWHERE)
RoomSave_mark_dirty_room(__rs_room);
IS_CARRYING_W(ch) += GET_OBJ_WEIGHT(object);
IS_CARRYING_N(ch)++;
@ -440,6 +445,7 @@ void obj_to_char(struct obj_data *object, struct char_data *ch)
void obj_from_char(struct obj_data *object)
{
struct obj_data *temp;
room_rnum __rs_room = IN_ROOM(object->carried_by);
if (object == NULL) {
log("SYSERR: NULL object passed to obj_from_char.");
@ -455,6 +461,8 @@ void obj_from_char(struct obj_data *object)
IS_CARRYING_N(object->carried_by)--;
object->carried_by = NULL;
object->next_content = NULL;
if (__rs_room != NOWHERE)
RoomSave_mark_dirty_room(__rs_room);
}
/* Return the effect of a piece of armor in position eq_pos */
@ -689,6 +697,8 @@ void obj_to_room(struct obj_data *object, room_rnum room)
object->carried_by = NULL;
if (ROOM_FLAGGED(room, ROOM_HOUSE))
SET_BIT_AR(ROOM_FLAGS(room), ROOM_HOUSE_CRASH);
/* RoomSave: this rooms contents changed */
RoomSave_mark_dirty_room(room);
}
}
@ -697,6 +707,7 @@ void obj_from_room(struct obj_data *object)
{
struct obj_data *temp;
struct char_data *t, *tempch;
room_rnum __rs_was_room = IN_ROOM(object);
if (!object || IN_ROOM(object) == NOWHERE) {
log("SYSERR: NULL object (%p) or obj not in a room (%d) passed to obj_from_room",
@ -719,6 +730,8 @@ void obj_from_room(struct obj_data *object)
SET_BIT_AR(ROOM_FLAGS(IN_ROOM(object)), ROOM_HOUSE_CRASH);
IN_ROOM(object) = NOWHERE;
object->next_content = NULL;
/* RoomSave: room lost an object */
RoomSave_mark_dirty_room(__rs_was_room);
}
/* put an object in an object (quaint) */
@ -735,6 +748,8 @@ void obj_to_obj(struct obj_data *obj, struct obj_data *obj_to)
obj->next_content = obj_to->contains;
obj_to->contains = obj;
obj->in_obj = obj_to;
/* RoomSave: container changed; mark the room the container ultimately lives in */
RoomSave_mark_dirty_room(RoomSave_room_of_obj(obj_to));
/* Add weight to container, unless unlimited. */
if (GET_OBJ_VAL(obj->in_obj, 0) > 0) {
@ -752,6 +767,7 @@ void obj_to_obj(struct obj_data *obj, struct obj_data *obj_to)
void obj_from_obj(struct obj_data *obj)
{
struct obj_data *temp, *obj_from;
struct obj_data *__rs_container = obj->in_obj; /* capture before unlink */
if (obj->in_obj == NULL) {
log("SYSERR: (%s): trying to illegally extract obj from obj.", __FILE__);
@ -772,6 +788,8 @@ void obj_from_obj(struct obj_data *obj)
}
obj->in_obj = NULL;
obj->next_content = NULL;
/* RoomSave: container changed; mark the room the container ultimately lives in */
RoomSave_mark_dirty_room(RoomSave_room_of_obj(__rs_container));
}
/* Set all carried_by to point to new owner */
@ -789,6 +807,7 @@ void extract_obj(struct obj_data *obj)
{
struct char_data *ch, *next = NULL;
struct obj_data *temp;
room_rnum __rs_room = RoomSave_room_of_obj(obj);
if (obj->worn_by != NULL)
if (unequip_char(obj->worn_by, obj->worn_on) != obj)
@ -837,6 +856,9 @@ void extract_obj(struct obj_data *obj)
if (GET_OBJ_RNUM(obj) == NOTHING || obj->proto_script != obj_proto[GET_OBJ_RNUM(obj)].proto_script)
free_proto_script(obj, OBJ_TRIGGER);
if (__rs_room != NOWHERE)
RoomSave_mark_dirty_room(__rs_room);
free_obj(obj);
}

View file

@ -13,6 +13,7 @@
#include "conf.h"
#include "sysdep.h"
#include <stdlib.h>
#include <dirent.h>
#include <errno.h>
#include <limits.h>
@ -36,6 +37,28 @@
#define ROOMSAVE_EXT ".rsv"
#endif
static unsigned char *roomsave_dirty = NULL;
void RoomSave_init_dirty(void) {
free(roomsave_dirty);
roomsave_dirty = calloc((size_t)top_of_world + 1, 1);
}
void RoomSave_mark_dirty_room(room_rnum rnum) {
if (!roomsave_dirty) return;
if (rnum != NOWHERE && rnum >= 0 && rnum <= top_of_world)
roomsave_dirty[rnum] = 1;
}
/* Where does an object “live” (topmost location -> room)? */
room_rnum RoomSave_room_of_obj(struct obj_data *o) {
if (!o) return NOWHERE;
while (o->in_obj) o = o->in_obj;
if (o->carried_by) return IN_ROOM(o->carried_by);
if (o->worn_by) return IN_ROOM(o->worn_by);
return o->in_room;
}
/* --- helper: read a list of objects until '.' or 'E' and return the head --- */
static struct obj_data *roomsave_read_list(FILE *fl) {
char line[256];
@ -397,8 +420,9 @@ void RoomSave_boot(void) {
/* Save all rooms flagged ROOM_SAVE. Called from point_update() on a cadence. */
void RoomSave_autosave_tick(void) {
for (room_rnum rnum = 0; rnum <= top_of_world; rnum++) {
if (ROOM_FLAGGED(rnum, ROOM_SAVE)) {
RoomSave_now(rnum);
}
if (!ROOM_FLAGGED(rnum, ROOM_SAVE)) continue;
if (!roomsave_dirty || !roomsave_dirty[rnum]) continue;
if (RoomSave_now(rnum))
roomsave_dirty[rnum] = 0;
}
}
}

View file

@ -25,4 +25,10 @@ int RoomSave_now(room_rnum rnum);
/* Autosave pass for all rooms flagged ROOM_SAVE. */
void RoomSave_autosave_tick(void);
/* Only save rooms when modified */
void RoomSave_init_dirty(void);
void RoomSave_mark_dirty_room(room_rnum rnum);
/* For container edits: find the room an object ultimately lives in */
room_rnum RoomSave_room_of_obj(struct obj_data *obj);
#endif /* ROOMSAVE_H_ */