Skip to content

sv_neo_restore_... - Give XP/deaths to players, restore from backup#1880

Open
nullsystem wants to merge 3 commits into
NeotokyoRebuild:masterfrom
nullsystem:GH-1878_GiveXP
Open

sv_neo_restore_... - Give XP/deaths to players, restore from backup#1880
nullsystem wants to merge 3 commits into
NeotokyoRebuild:masterfrom
nullsystem:GH-1878_GiveXP

Conversation

@nullsystem

@nullsystem nullsystem commented Mar 21, 2026

Copy link
Copy Markdown
Collaborator

Description

Native implementation of XP/deaths restoration, with an extra to automatically backup and manually restore whole session.

ConVars:

  • sv_neo_restore_xp_death_any_round - Allow setting XP/session anytime
  • sv_neo_restore_session_allow_name_match - Allow name matching
    in session restore

Commands:

  • sv_neo_restore_session - Restore entire session from backup
  • sv_neo_restore_round_number - Force round number
  • sv_neo_restore_rounds_won - Force Jinrai/NSF rounds won
  • sv_neo_restore_team_scores - Force Jinrai/NSF scores
  • sv_neo_restore_xp - Force XP on a player

Removed commands:

  • sv_neo_score_set_[jinrai/nsf] - Replaced by sv_neo_restore_... equivalent

Toolchain

  • Linux GCC Distro Native Arch/GCC 15

Linked Issues

@nullsystem nullsystem force-pushed the GH-1878_GiveXP branch 2 times, most recently from ab33a72 to 5b230b8 Compare March 22, 2026 02:25
@nullsystem nullsystem changed the title [WIP] TODO: .givexp/.givexpall - Give XP to players from authorized spec … sv_neo_force_... - Give XP/deaths to players, restore from backup Mar 22, 2026
@nullsystem nullsystem marked this pull request as ready for review March 22, 2026 02:26
@nullsystem nullsystem marked this pull request as draft March 22, 2026 02:26
@nullsystem nullsystem marked this pull request as ready for review March 22, 2026 02:34
@nullsystem nullsystem changed the title sv_neo_force_... - Give XP/deaths to players, restore from backup sv_neo_restore_... - Give XP/deaths to players, restore from backup Mar 22, 2026
@nullsystem nullsystem marked this pull request as draft March 22, 2026 18:11
@nullsystem nullsystem force-pushed the GH-1878_GiveXP branch 5 times, most recently from d228e68 to 565f240 Compare March 23, 2026 20:38
@nullsystem nullsystem marked this pull request as ready for review March 23, 2026 20:39
@nullsystem nullsystem force-pushed the GH-1878_GiveXP branch 2 times, most recently from 6bff179 to 00bfcda Compare March 23, 2026 20:42
@nullsystem nullsystem requested a review from a team March 23, 2026 20:42
@nullsystem nullsystem force-pushed the GH-1878_GiveXP branch 2 times, most recently from ae245ea to 9851d32 Compare March 23, 2026 22:24
Comment thread src/game/server/neo/neo_player.h Outdated
@sunzenshen sunzenshen requested a review from a team March 24, 2026 07:24
Native implementation of XP/deaths restoration, with an extra to
automatically backup and manually restore whole session.

ConVars:
* `sv_neo_restore_xp_death_any_round` - Allow setting XP/session anytime
* `sv_neo_restore_session_allow_name_match` - Allow name matching
  in session restore

Commands:
* `sv_neo_restore_session` - Restore entire session from backup
* `sv_neo_restore_round_number` - Force round number
* `sv_neo_restore_rounds_won` - Force Jinrai/NSF rounds won
* `sv_neo_restore_team_scores` - Force Jinrai/NSF scores
* `sv_neo_restore_xp` - Force XP on a player

* fixes NeotokyoRebuild#1878
@Agiel

Agiel commented Mar 24, 2026

Copy link
Copy Markdown
Contributor

We already have commands for setting team score introduced in #1638. Might want to remove those to avoid confusion?

@nullsystem

Copy link
Copy Markdown
Collaborator Author

@Agiel Removed them now: 3419390

static inline bool InLiveState()
{
return (NEORules()->GetRoundStatus() == RoundLive || NEORules()->GetRoundStatus() == PostRound);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Would it make more sense to put the above two in neo_gamerules?

{
if (iRoundNumber < 0)
{
Msg("%s: error: Cannot have negative round number\n", pszFuncName);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Use void Error(const tchar *pMsg, ...) for error messages

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just thought id note may not want to use error for this case and the ones below unless you actually think it should stop the program, warning is probably better

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

if error is the really dark red one and warning the light red one then yeah warning is probably better

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ah i see Error doesn't return

{
if (iRoundsWonJinrai < 0 || iRoundsWonNSF < 0)
{
Msg("%s: error: Cannot have negative rounds won\n", pszFuncName);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ditto void Error(const tchar *pMsg, ...)

{
if (false == sv_neo_restore_xp_death_any_round.GetBool() && false == InReadyUpState())
{
Msg("%s: error: Cannot set XPs if not idle and in a ready up lobby\n", __func__);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ditto void Error(const tchar *pMsg, ...)

KeyValues *kv = new KeyValues(GIVEXP_SESSION_RESTORE_KV_ROOT);
if (false == kv->LoadFromFile(g_pFullFileSystem, "scripts/" GIVEXP_SESSION_RESTORE_FNAME))
{
Msg("%s: error: No restore session file found\n", __func__);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ditto void Error(const tchar *pMsg, ...)


const char *pszNameFind = args[1];
const int iXP = V_atoi(args[2]);
if (false == IN_BETWEEN_EQ(-99, iXP, 1000))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:ebussi:

{
Msg((iDeaths < 0)
? "%s: error: Death count must be positive\n"
: "%s: error: Unresonable death count\n"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

:ebussi:

const int iDeaths = (args.ArgC() == 4) ? V_atoi(args[3]) : -1;
if (4 == args.ArgC() && false == IN_BETWEEN_EQ(0, iDeaths, 1000))
{
Msg((iDeaths < 0)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ditto void Error(const tchar *pMsg, ...)


if (false == sv_neo_restore_xp_death_any_round.GetBool() && false == InReadyUpState())
{
Msg("%s: error: Cannot set XPs if not idle and in a ready up lobby\n", __func__);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ditto void Error(const tchar *pMsg, ...)

}
}

Msg("%s: error: Cannot find player \"%s\"\n", __func__, pszNameFind);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

ditto void Error(const tchar *pMsg, ...)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Native implemention of giving players XP

5 participants