Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 54 additions & 36 deletions programs/utilities/keepalive.sc
Original file line number Diff line number Diff line change
@@ -1,45 +1,63 @@
// re-logs fake players upon server restart
// must need to place it directly in the world scripts folder

__config() -> {'scope' -> 'global'};

__spawn_players() -> (
data = load_app_data();
if (data && data:'players',
data = parse_nbt(data:'players');
for (data,
for([str('player %s spawn at %f %f %f facing %f %f in %s',
_:'name', _:'x', _:'y', _:'z', _:'yaw', _:'pitch', _:'dim'),
str('gamemode %s %s', _:'gm', _:'name')],
logger('warn', _);
run(_);
);
modify(player(_:'name'), 'flying', _:'fly')
)
);
global_cached_players = {};

__config() -> {
'scope' -> 'global'
};

__on_player_connects(player) -> (
player_name = player()~'name';

if (has(global_cached_players, player_name),
Copy link
Collaborator

Choose a reason for hiding this comment

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

After checking this, i would suggest removing the entry from the map too. After all the player might be spawned multiple times in different gamemodes manually later.
For example:

  • /player test spawn in creative (Spawn flying player in the air)
  • Reopen server, script spawns player back in creative and correctly sets flying to true
  • /player test kill
  • /player test spawn in survival
    Now you got a flying player in survival, since it still saved that test should be flying

Copy link
Author

@VoidedBlades VoidedBlades Jun 20, 2025

Choose a reason for hiding this comment

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

rather than removing the map i reckon it may be better to clear the key from the map on __on_player_disconnects?
this would support utilizing the map for any future usages where needed alongside removing the obstructions mentioned.

Ive tried moving the task into __on_server_starts as well as a hopeful functioning alternative but alas. it has to be through __on_player_connects of sorts

Copy link
Collaborator

Choose a reason for hiding this comment

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

That would work too, though i don't see any use for that currently.

Do you have any more details on why modify is not working if you use a task? Is the player not available?

Copy link
Author

@VoidedBlades VoidedBlades Jun 20, 2025

Choose a reason for hiding this comment

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

the player is not available during __on_server_starts but afterwards during the __on_player_connects it is obviously, no errors seem to happen even removing the task inside of __on_player_connects however when entering the server the actual modification hasnt happened without said task and the player is on the ground but in creative.

im assuming this is due to some sort of race condition between a form of post initialization of the player and the value modified, in this case the flying.

its an incredibly peculiar situation nontheless.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Just to confirm, you are still using the schedule(0, _(e) -> (modify(player(e:'name'), 'flying', e:'fly')), e); right?
It's true that the flying state of the player is set after the player_connects event is fired, which would overwrite that if modify was used directly in the event. Scheduling to the end of the tick should fix that though.
As far as i can tell, there is no asynchronous initialization of the player, it all happens right after.

Copy link
Author

@VoidedBlades VoidedBlades Jun 20, 2025

Choose a reason for hiding this comment

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

ive pushed a new update, its still using schedule and at the time was too to modify it so everything should be fine now i reckon? do let me know if anything else needs adjusting!

e = global_cached_players:player_name;
if(e:'gm' == 'creative' && e:'fly' == 1,
// scheduling the modification at the end to ensure the entity was created properly and setting it to the intended state
schedule(0, _(e) -> (modify(player(e:'name'), 'flying', e:'fly')), e);
);
)
);

__on_player_disconnects(player, reason) -> (
player_name = player()~'name';

if (has(global_cached_players, player_name),
global_cached_players:str(player_name) = null;
);
);

__on_server_starts() -> (
task('__spawn_players');
data = load_app_data();
Copy link
Collaborator

Choose a reason for hiding this comment

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

Loading this data on every player connection (even non fake ones and after server startup) feels unnecesary. I would suggest loading this data once in __on_connect and storing it in a global variable (ideally converted to a map with the player names as keys for quick access, instead of the foor loop in line 29). Then on every connect you can just check if the connected player's name is in that map. If so, change the gamemode and remove it from the map, so future connections of this player won't have it's gamemode changed.


if (data && data:'players',
data = parse_nbt(data:'players');
for (data,
global_cached_players:str(_:'name') = _;
run(str('player %s spawn at %f %f %f facing %f %f in %s in %s', _:'name', _:'x', _:'y', _:'z', _:'yaw', _:'pitch', _:'dim', _:'gm'))
);
);
);

__on_server_shuts_down() -> (
data = nbt('{players:[]}');
saved = [];
for (filter(player('all'), _~'player_type' == 'fake'),
pdata = nbt('{}');
pdata:'name' = _~'name';
pdata:'dim' = _~'dimension';
pdata:'x' = _~'x';
pdata:'y' = _~'y';
pdata:'z' = _~'z';
pdata:'yaw' = _~'yaw';
pdata:'pitch' = _~'pitch';
pdata:'gm' = _~'gamemode';
pdata:'fly' = _~'flying';
put(data, 'players', pdata, -1);
saved += _~'name';
);
store_app_data(data);
if (saved, logger('warn', 'saved '+saved+' for next startup'));
);
data = nbt('{players:[]}');
saved = [];

for (filter(player('all'), _~'player_type' == 'fake'),
pdata = nbt('{}');
pdata:'name' = _~'name';
pdata:'dim' = _~'dimension';
pdata:'x' = _~'x';
pdata:'y' = _~'y';
pdata:'z' = _~'z';
pdata:'yaw' = _~'yaw';
pdata:'pitch' = _~'pitch';
pdata:'gm' = _~'gamemode';
pdata:'fly' = _~'flying';
put(data, 'players', pdata, -1);
saved += _~'name';
);

store_app_data(data);
if (saved, logger('warn', 'saved '+saved+' for next startup'));
);