Skip to content
NordBots.
Back to Checkpoint

Checkpoint configuration

The Checkpoint config.json controls how the plugin runs on your Ark Survival Ascended server. Every setting is listed below with what it does and its default value.

Open the configuration editorPrefer clicking to typing? Build the file with sliders and toggles.

Where it lives

Drop the file on your server at ArkApi/Plugins/Checkpoint/config.json then reload the plugin or restart the server. Keep a backup before large changes.

Every setting

Language

Which language file to use out of the lang folder. "en" reads lang/en.json. Copy en.json to de.json, translate it, and put "de" here.

LangAutoFill

When I get an update with new lines in it, add the new lines to your language file and leave every line you wrote alone. Your old file is kept beside it as a .bak. Set this to false and I will never touch your files.

SenderName

The name shown in front of my chat messages. Leave it empty and the game shows the usual (SERVER): prefix. Put anything in and that name is used instead. {map} and {server} both work here.

Server

How I work out what to call this server in Discord posts and in my records.

Name
textempty
Set this and I use it, no questions asked. Best option if you know it.
NameFromParams
list["-ServerName=","-serverkey=","-clustermap=","?SessionName="]
If Name is empty I read your launch line and take whatever follows one of these. First one found wins. Handy on a cluster, where every map has a different -ServerName= and you want the posts to say which map.
UseSessionName
togglefalse
Last resort before the map name: use the session name players see in the server browser. Off by default because it is often long and messy.
Id
textempty
A short tag for me to use in the database, like "island" or "pvp2". Leave it empty and I make one from the name above.

General

Debug
togglefalse
Turn this on and I explain what I am doing in ArkApi.log: which door I caught a joining player at, what an address lookup cost, whether a permission check said yes. Off by default so the log stays quiet. Turn it on when something looks wrong, then turn it back off.

Commands

What players type. Rename any of these to whatever your players expect. Set one to an empty string and that command is not registered at all.

WishCMD
text"/tpr"
Ask to travel to somebody: /tpr Dave
SummonCMD
text"/tph"
Ask somebody to come to you: /tph Dave
AcceptCMD
text"/tpa"
Say yes. With more than one person waiting, /tpa #2 or /tpa Dave.
DenyCMD
text"/tpd"
Say no. /tpd all clears every ask at once.
CancelCMD
text"/tpc"
Drop the ask you sent.
ListCMD
text"/tpl"
See who is waiting on you, numbered.
InfoCMD
text"/tpinfo"
Your cooldown, your count for today, and why the last one was refused.
StaffCMD
text"/ck"
The small staff command in chat: /ck who Dave, /ck ban, /ck mute. Everything bigger lives on the console and RCON, where there is room.
MineCMD
text"/banned"
A player checks their own state: am I banned, am I muted, when does it end. This one line saves a lot of staff messages.

Gate

The ban side of me.

Enabled
toggletrue
Turn this off and I stop turning anybody away. I still keep records, so you can look at who is joining without enforcing anything yet. A good way to start: run with this off for a week and read Checkpoint.Where.
RefreshSeconds
number30
How often I read the ban list back out of the database, in seconds. This is what makes a ban placed on one map bite on another. Only matters on MySQL. On SQLite there is nothing to read from another server.
ClusterWide
togglefalse
Should a new ban count on every map that shares this database, or only this one? Off means this map only, and you can still say --cluster on a single ban when you mean it. Turn it on if you run a cluster and want one ban to cover everything.
ShowReasonToPlayer
toggletrue
Show the refused player the reason and the end date. On by default, because "the server just says failed to connect" is the number one question a banned player asks, and this answers it for you.
ReasonRequired
toggletrue
Refuse to place a ban with no reason written on it. On by default. In six months somebody will read that ban and want to know why it is there.
RefusedLine
text"You cannot join this server."
The first line a refused player reads.
RefusedBlockLine
text"This connection is blocked, not you personally."
The line for somebody caught by a range or a company ban rather than by name. Worth keeping separate: it is often an innocent neighbour.
ScreenedLine
text"This server does not take connections like yours. Turn off any VPN or proxy and try again."
The line for somebody turned away by the Screen block below.
AppealLine
textempty
Added to the end of every refusal. Put your Discord invite or your site here so an honest player who was caught by mistake knows where to go.
AutoBanEvaders
togglefalse
When a brand new account joins from a connection that already carries a ban, should I ban it on the spot? OFF by default and I mean it. A shared house, a flat share and a mobile carrier all look the same as an evader. With this off I post the evidence to your alert channel and you decide.
PostArrivals
togglefalse
Post a line to your join channel every time somebody arrives, with their country and connection. Off by default because on a busy server that is a lot of posts. Turn it on for a week when you are chasing somebody.
ConfirmWiderThan
number24
A range ban narrower than this many bits needs a confirm code before it takes. 24 means a /24 goes straight through and a /23 or wider asks first, and tells you how many of your own past logins it would have refused. Lower this if you want to be asked less. Do not raise it above 32, that would make every single address ban ask.
ConfirmSeconds
number300
How long a confirm code stays good for, in seconds.
BansPerPage
number20
How many bans Checkpoint.Bans shows on one page.
LoginsShown
number15
How many past logins Checkpoint.Logins shows for one player.
OpenMinutes
number10
How long Checkpoint.Open switches every ban check off for, in minutes, when you do not name a number. This is your way back in if you ever ban yourself, because RCON does not go through the ban check.

Screen

Refusing a connection for what it is rather than who is on it. Every one of these needs geo data with the threat flags on, so they do nothing until you put an ipgeolocation key in geo.json and set Geo.Security to true. All off by default, and please think before turning any on. Plenty of ordinary players use a VPN for everything they do.

BlockVpn
togglefalse
Somebody the geo service says is on a VPN.
BlockProxy
togglefalse
Somebody on a proxy.
BlockTor
togglefalse
Somebody coming out of the Tor network.
BlockHosting
togglefalse
Somebody connecting from a data centre rather than a home line. This one catches bots and people scouting for a DDoS, and it also catches a real player behind a work tunnel. The most useful of the four and the one most likely to annoy somebody honest.
MaxThreat
number0
Refuse anybody the service scores at or above this, 1 to 100. 0 is off. Start at 90 if you want to try it, and watch your alert channel first.
WarnOnly
toggletrue
TRUE means I only tell you, I never refuse anybody. Leave this true for a week before you set it false. You will be surprised who gets caught.

Geo

Looking an address up so you can see where a player is and whether the connection is hiding something. Your key goes in geo.json, not here.

Enabled
togglefalse
Off by default. Everything else in the plugin works without it. Bans on an account, an address or a range all work with this off. What you lose is country and company bans, the VPN flags, and the country report.
Security
togglefalse
Ask for the VPN, proxy, Tor and threat flags as well as the location. On ipgeolocation this makes each new address cost 3 credits instead of 1, so a free 1000 a day key covers about 333 new players instead of 1000. I print that sum in the log at startup using your own settings.
StrictGate
togglefalse
What to do about a player whose address I have never looked up, when you have a country or company ban in place. false, the default: let them in, look it up, and remove them a second later if the answer says they are banned. First join gets through, every later one is refused at the door. true: refuse them and ask them to try again in a moment, so nobody ever gets in. Correct, and it turns a slow service into a server nobody can join. Only use this if you know what it costs.
TtlDays
number30
How long I trust an answer before asking again, in days.
MaxPerDay
number300
A hard ceiling on lookups a day, counted by me. Stops a join flood or a bot sweep burning a month of credits in an hour. 0 means no ceiling.
MinSecondsBetween
number1
Seconds between lookups. One at a time, always. A restart with 60 players trickles instead of firing 60 web requests at once.
QueueMax
number500
How many addresses I will hold waiting to be looked up.

Mute

Keeping somebody out of chat.

Enabled
toggletrue
If you already run WarnSystem, leave this alone. I check for it at startup and step aside, because two plugins muting people means your staff never know which one did it.
DefaultKind
text"chat"
What a mute does when nobody says otherwise. "chat" their chat lines are dropped, their commands still work "all" chat and commands both dropped "quiet" they see their own lines and nobody else does A word about "quiet". It is a real moderation tool: a loud player who knows they are muted makes a new account inside five minutes, one who does not know keeps talking to an empty room and gets bored. It is also the kind of thing to use on purpose, not by accident, so it is not the default and this comment says plainly what it does.
EscalateWindowDays
number30
Repeat offences inside this many days climb the ladder below. Set it to 0 and every mute starts at the first rung again.
Ladder
list[5,30,120,1440,10080]
How long a mute lasts, in minutes, the first time, the second time, and so on. The last one repeats forever. Used when you mute somebody without naming a length yourself. 10080 is a week.

Privacy

An IP address counts as personal data in the EU and the UK, and it is you who holds it, not me. So these settings default to careful and everything here actually happens. The retention lines below are real deletes.

StoreFullIp
toggletrue
TRUE keeps the whole address so your staff can read it. FALSE keeps a salted hash plus the /24 and the company, and nothing else. Everything still works in that mode: an exact address ban compares a hash against a hash just fine, a range ban only needs the /24, and the reports still read. The only thing you lose is being able to read an address on screen. If that trade suits you, this is a genuinely usable mode and not a token one. The salt is made once and kept in geo.json.
KeepLoginDays
number90
Login rows older than this many days are deleted. Really deleted, once a day, not hidden behind a flag. 0 means keep them forever, which is a choice you are making on purpose.
KeepGeoDays
number365
Same, for the address lookups I have cached.
HashAfterDays
number0
Above 0, an address is swapped for its hash after this many days while the login row itself stays. A middle road between the two modes above.
RedactInDiscord
toggletrue
A public Discord post shows 203.0.113.*** instead of the whole address. The whole value only ever goes to AlertWebhookURL.
RedactInPanel
toggletrue
Same for the in game window.
SeeIpNode
text"Checkpoint.SeeIp"
The one permission node that lets somebody read a whole address anywhere. Give it to the people you would trust with your own.

SafeList

Nothing on this list can ever be refused by any ban of any kind. Put yourself on it before you ban a single range. I say so in the log at startup while it is empty, and if you do lock yourself out anyway, run Checkpoint.Open from RCON.

Eos
list[]
Exact EOS ids. Yours goes here.
Ips
list[]
Exact addresses. Your home line and your office, if you like.
Cidrs
list[]
Whole ranges, written like 203.0.113.0/24.
Nodes
list["Checkpoint.Immune"]
Anybody holding one of these permission nodes is safe. The tidiest option, because it follows your staff group and you never touch this file again when somebody joins or leaves the team.

Watch

Noticing things and telling you, rather than acting on them.

LinkWindowDays
number30
Two accounts have to share a connection inside this many days for me to call them linked.
LinksShown
number8
How many linked accounts to show in one report.
CountriesShown
number10
How many countries Checkpoint.Where lists.
AlertOnEvader
toggletrue
Tell your alert channel when a fresh account joins from a connection that carries a ban. I only tell you. I never act on it unless you turned Gate.AutoBanEvaders on.
AlertOnOddTravel
toggletrue
Tell your alert channel when one account joins from two places too far apart to be one person travelling. Usually a VPN being switched, and sometimes two people sharing a login.
ImpossibleTravelKmH
number900
How fast is too fast, in kilometres an hour. 900 is roughly a passenger jet, so anything above it is not somebody who got on a plane.
ImpossibleTravelMinKm
number500
Ignore hops shorter than this many kilometres. Stops a normal city to city move from looking odd just because the clock was tight.
LinkCaveat
text"One house, one flat share, a school or a mobile carrier all look exactly like this. A Weak line on its own means almost nothing."
Printed at the bottom of every link report, every time. Say it in your own words if you like, but please keep saying something, because a household and an alt account leave exactly the same trail.

Travel

Player to player travel.

Enabled
toggletrue
Turn this off and I am a moderation plugin only, with no travel commands registered at all. If you already run TeleportRequest, I notice it at startup and step aside on my own, because we both want /tpa.
AllowSummon
toggletrue
Allow /tph, asking somebody to come to you. They still have to say yes. Turn it off and travel only ever goes one way, towards the other person.
RequestTimeoutSeconds
number45
How long an ask sits there before I give up on it, in seconds.
CooldownSeconds
number120
How long a player waits between travels, in seconds.
PairCooldownSeconds
number300
How long the SAME TWO players wait before travelling to each other again, in seconds. This is the one that stops two friends using each other as a free taxi across the map all day. 0 turns it off.
MaxPerDay
number0
Most travels one player gets in a day. 0 means no limit.
MaxDistance
number-1
Refuse a travel longer than this, in game units. -1 means any distance. Roughly 100000 is a fair chunk of a map if you want to try a number.
WarmupSeconds
number5
Hold the mover still for this many seconds before they go. If anything hits either of them, or they walk off, I stop and hand their points back. 0 makes travel instant, which players like and raiders like more.
WarmupMoveTolerance
number300
How far the mover may drift during the warmup before I call it off.
CheckForDino
toggletrue
Refuse a travel when either player is on a dino. On by default, because a dino left behind mid warp is a support ticket.
BlockWhileFalling
toggletrue
Stop the warmup if the mover is dropping. Catches somebody using travel to cancel a fall.
FallingDrop
number400
How far they have to drop in one second for me to call it falling.
PointCost
number0
Points each travel costs the asker, charged when the other player says yes and handed straight back if the travel then fails for any reason. 0 makes travel free. Needs ArkShop or WShop, and if neither is installed travel is free and I say so once in the log rather than breaking.
AbuseStrikes
number5
Refusals in a row that earn a player a time out. A player who tries nine times to warp into a raid is telling you something, and this is where I stop being polite and post to your alert channel.
AbuseWindowMinutes
number10
The window those refusals have to land in, in minutes.
AbusePenaltySeconds
number900
How long the time out lasts, in seconds.

Gates

When travel is shut. These are the settings that separate a travel plugin people keep from one they uninstall after their first bad raid.

CombatSeconds
number20
Nobody travels for this many seconds after either player was in a fight.
RaidSeconds
number300
Nobody travels into or out of a tribe that is being raided, or that is doing the raiding, for this many seconds after the last hit on a base. This is the important one. Without it, twelve defenders warp in one after another the moment a raid starts, because a travel request is faster than a bird. 300 is five minutes and is a sensible place to start. Set it to 0 only if your server has no raiding at all.
RelaxOnPve
toggletrue
On a PvE server the two gates above are pointless, so I switch them off and say so at startup. I read whether you are PvE from the game itself.

Targeting

How I turn what somebody typed into one exact player. Every command that takes a player name uses this, in chat and on RCON both. It already handles: the survivor name, the account name, a bare EOS id, char: name: tribe: id: and eos: prefixes, a quoted name, #2 to pick off the list I just showed, accents, Cyrillic and Greek letters that look Latin, fullwidth and circled letters, xX_tags_Xx, and leet like 5n4k3.

MatchCharacterName
toggletrue
Match the survivor name, the one over their head. Players type this one.
MatchPlatformName
toggletrue
Match the account name from Steam, Xbox or PlayStation.
MatchTribeName
toggletrue
Match a tribe name, then let you pick a member. Scored below a person, so a player called Wolves always beats a tribe called Wolves.
MatchOldNames
toggletrue
Match a name they used to wear. Stops a rename shaking off a ban.
AllowOffline
toggletrue
Let staff commands find somebody who is not online. On, because banning an offline player is the normal case. Travel always needs them online.
OfflineDays
number30
How far back to look for an offline player, in days.
FuzzyTypos
toggletrue
Allow for typing mistakes. Turn it off and only real names match.
MaxTypos
number2
Most mistakes allowed in a longer name. Short names get fewer on their own, so Dob can find Bob without Dob finding Cat.
MinTypoLength
number3
Do not allow mistakes in anything shorter than this many letters.
ShowChoices
number5
How many to show when more than one player matches. When two are equally good I never guess, I show the list and you answer with a number.
PickSeconds
number90
How long that numbered list stays good for, in seconds.
RecentMinutes
number10
How long "last" reaches back for whoever last asked you to travel, in minutes.

Permissions

Who is allowed to do what. Needs the free Permissions plugin. Without it, staff chat commands say no to everybody and the console and RCON still work, which is where the real power is anyway.

Enabled
toggletrue
TravelNode
text"Checkpoint.Travel"
Players need this to use travel at all. With Permissions missing this one fails OPEN, so travel keeps working on a server that does not run it.
WhoNode
text"Checkpoint.Who"
Staff nodes. These all fail CLOSED, so a missing Permissions means no.
BanNode
text"Checkpoint.Ban"
MuteNode
text"Checkpoint.Mute"
KickNode
text"Checkpoint.Kick"
AltsNode
text"Checkpoint.Alts"
FasterFor
group
A shorter travel cooldown for people holding a node. Add as many lines as you like. The shortest one they qualify for wins.
Checkpoint.Vip
number30

ArkShop

The points shop, only used if you set Travel.PointCost above 0.

Enabled
toggletrue
Provider
text"Auto"
"Auto" takes ArkShop if it is running, then WShop. Name one on purpose if you run both, which almost nobody does.

Database

Where my records live. This one is worth reading properly, because it is the difference between a ban that covers one map and a ban that covers all of them.

UseMySQL
togglefalse
FALSE uses SQLite, a single file in my data folder, with nothing to set up. Perfect for one server. TRUE uses MySQL, and then every map pointed at the same database shares one ban list, one set of records and one view of who is linked to whom. On a cluster that is the whole point. Set Gate.ClusterWide to true as well, or a ban still only covers the map it was placed on.
SQLiteDatabasePath
textempty
Where to put the SQLite file. Leave it empty and I use my own data folder, which is what you want. It is the folder to copy if you ever want a backup of every ban you have placed.
TablePrefix
text"checkpoint"
The front of all seven of my table names. Change it if something else is already using these names in your database.
Host
text"127.0.0.1"
MySQL only, all ignored on SQLite.
Port
number3306
User
textempty
Password
textempty
Database
textempty
MysqlSSLMode
number-1
Leave these two alone unless your host told you otherwise. -1 and empty mean use whatever the server and the client agree on.
MysqlTLSVersion
textempty

ApiUtilsMod

On screen messages through the free ASA API Utils mod. The mod is a nice to have and never required. Without it I talk in chat instead and say so once in the log.

Enabled
toggletrue
BackdropColor
list[0,0,0,0.55]
The box behind the words: red, green, blue, and how solid, each 0.0 to 1.0. The last number is the one to change. 0.55 is a soft dark box.
ScreenPosition
text"Center"
Where on screen: "Left", "Center" or "Right".
TextAlign
text"Center"
How the words sit in the box: "Left", "Center" or "Right".
TextScale
number1
Bigger than 1.0 is bigger text.
MessageSeconds
number6
How long a message stays up, in seconds.
AlsoShowInChat
toggletrue
Also put the same words in the chat log, so a player can scroll back to a warmup countdown or a mute notice they missed. This does mean two messages per send, which is fine.

MapName

The game gives me level names like TheIsland_WP, which no player should ever read.

Pretty
toggletrue
Tidy it up into The Island. Turn it off to see the raw name.
Overrides
group
Or write your own, for a map I get wrong or a modded one. Example: { "Svartalfheim_WP": "Svartalfheim" }

Panel

The in game window from the NordBots UI mod. Players get a Travel pane with buttons for who is waiting on them, and staff with the right nodes get an arrivals pane and a bans pane. A button press runs the exact same command the chat version runs, with the same permission check, so the window is never a way around anything.

Enabled
toggletrue
Off means I never open a window. Every chat command still works.
RowsPerPage
number8
Rows in one pane before it pages.
TopCount
number10
How many rows a top list shows.
BuffTag
text"NordBotsUIBuff"
Leave these three alone unless the mod tells you to change them.
BuffPath
text"NordBotsUI/Buff_NordBotsUI"
SingletonPath
text"Blueprint'/NordBotsUI/NordBotsUI_Singleton.NordBotsUI_Singleton'"
RequireHandshake
togglefalse
Wait for the mod to say hello before I send it anything. Off is fine and is what almost everybody wants.

The full commented config

This is a reading copy with notes. It is not valid JSON, so do not load it. Use the editor or the plain config.json instead.

// Checkpoint, config.json explained
//
// This file is here to be read. It is not the file the plugin loads.
// The plugin reads config.json next to this one. Copy a line across when you
// want to change it, and keep config.json valid JSON with no comments in it.
//
// Two settings are NOT in this file on purpose:
//   Your Discord webhooks live in discord.json.
//   Your geo API key lives in geo.json.
// Both sit in this same folder. They are kept apart because they are secrets,
// and because a key in config.json ends up in every screenshot you ever share.
{
  // Which language file to use out of the lang folder. "en" reads lang/en.json.
  // Copy en.json to de.json, translate it, and put "de" here.
  "Language": "en",

  // When I get an update with new lines in it, add the new lines to your
  // language file and leave every line you wrote alone. Your old file is kept
  // beside it as a .bak. Set this to false and I will never touch your files.
  "LangAutoFill": true,

  // The name shown in front of my chat messages. Leave it empty and the game
  // shows the usual (SERVER): prefix. Put anything in and that name is used
  // instead. {map} and {server} both work here.
  "SenderName": "",

  // How I work out what to call this server in Discord posts and in my records.
  "Server": {
    // Set this and I use it, no questions asked. Best option if you know it.
    "Name": "",

    // If Name is empty I read your launch line and take whatever follows one
    // of these. First one found wins. Handy on a cluster, where every map has
    // a different -ServerName= and you want the posts to say which map.
    "NameFromParams": [
      "-ServerName=",
      "-serverkey=",
      "-clustermap=",
      "?SessionName="
    ],

    // Last resort before the map name: use the session name players see in the
    // server browser. Off by default because it is often long and messy.
    "UseSessionName": false,

    // A short tag for me to use in the database, like "island" or "pvp2".
    // Leave it empty and I make one from the name above.
    "Id": ""
  },

  "General": {
    // Turn this on and I explain what I am doing in ArkApi.log: which door I
    // caught a joining player at, what an address lookup cost, whether a
    // permission check said yes. Off by default so the log stays quiet.
    // Turn it on when something looks wrong, then turn it back off.
    "Debug": false
  },

  // What players type. Rename any of these to whatever your players expect.
  // Set one to an empty string and that command is not registered at all.
  "Commands": {
    // Ask to travel to somebody: /tpr Dave
    "WishCMD": "/tpr",

    // Ask somebody to come to you: /tph Dave
    "SummonCMD": "/tph",

    // Say yes. With more than one person waiting, /tpa #2 or /tpa Dave.
    "AcceptCMD": "/tpa",

    // Say no. /tpd all clears every ask at once.
    "DenyCMD": "/tpd",

    // Drop the ask you sent.
    "CancelCMD": "/tpc",

    // See who is waiting on you, numbered.
    "ListCMD": "/tpl",

    // Your cooldown, your count for today, and why the last one was refused.
    "InfoCMD": "/tpinfo",

    // The small staff command in chat: /ck who Dave, /ck ban, /ck mute.
    // Everything bigger lives on the console and RCON, where there is room.
    "StaffCMD": "/ck",

    // A player checks their own state: am I banned, am I muted, when does it end.
    // This one line saves a lot of staff messages.
    "MineCMD": "/banned"
  },

  // The ban side of me.
  "Gate": {
    // Turn this off and I stop turning anybody away. I still keep records, so
    // you can look at who is joining without enforcing anything yet. A good
    // way to start: run with this off for a week and read Checkpoint.Where.
    "Enabled": true,

    // How often I read the ban list back out of the database, in seconds.
    // This is what makes a ban placed on one map bite on another. Only matters
    // on MySQL. On SQLite there is nothing to read from another server.
    "RefreshSeconds": 30,

    // Should a new ban count on every map that shares this database, or only
    // this one? Off means this map only, and you can still say --cluster on a
    // single ban when you mean it. Turn it on if you run a cluster and want
    // one ban to cover everything.
    "ClusterWide": false,

    // Show the refused player the reason and the end date. On by default,
    // because "the server just says failed to connect" is the number one
    // question a banned player asks, and this answers it for you.
    "ShowReasonToPlayer": true,

    // Refuse to place a ban with no reason written on it. On by default. In six
    // months somebody will read that ban and want to know why it is there.
    "ReasonRequired": true,

    // The first line a refused player reads.
    "RefusedLine": "You cannot join this server.",

    // The line for somebody caught by a range or a company ban rather than by
    // name. Worth keeping separate: it is often an innocent neighbour.
    "RefusedBlockLine": "This connection is blocked, not you personally.",

    // The line for somebody turned away by the Screen block below.
    "ScreenedLine": "This server does not take connections like yours. Turn off any VPN or proxy and try again.",

    // Added to the end of every refusal. Put your Discord invite or your site
    // here so an honest player who was caught by mistake knows where to go.
    "AppealLine": "",

    // When a brand new account joins from a connection that already carries a
    // ban, should I ban it on the spot? OFF by default and I mean it. A shared
    // house, a flat share and a mobile carrier all look the same as an evader.
    // With this off I post the evidence to your alert channel and you decide.
    "AutoBanEvaders": false,

    // Post a line to your join channel every time somebody arrives, with their
    // country and connection. Off by default because on a busy server that is
    // a lot of posts. Turn it on for a week when you are chasing somebody.
    "PostArrivals": false,

    // A range ban narrower than this many bits needs a confirm code before it
    // takes. 24 means a /24 goes straight through and a /23 or wider asks
    // first, and tells you how many of your own past logins it would have
    // refused. Lower this if you want to be asked less. Do not raise it above
    // 32, that would make every single address ban ask.
    "ConfirmWiderThan": 24,

    // How long a confirm code stays good for, in seconds.
    "ConfirmSeconds": 300,

    // How many bans Checkpoint.Bans shows on one page.
    "BansPerPage": 20,

    // How many past logins Checkpoint.Logins shows for one player.
    "LoginsShown": 15,

    // How long Checkpoint.Open switches every ban check off for, in minutes,
    // when you do not name a number. This is your way back in if you ever ban
    // yourself, because RCON does not go through the ban check.
    "OpenMinutes": 10
  },

  // Refusing a connection for what it is rather than who is on it. Every one of
  // these needs geo data with the threat flags on, so they do nothing until you
  // put an ipgeolocation key in geo.json and set Geo.Security to true.
  //
  // All off by default, and please think before turning any on. Plenty of
  // ordinary players use a VPN for everything they do.
  "Screen": {
    // Somebody the geo service says is on a VPN.
    "BlockVpn": false,

    // Somebody on a proxy.
    "BlockProxy": false,

    // Somebody coming out of the Tor network.
    "BlockTor": false,

    // Somebody connecting from a data centre rather than a home line. This one
    // catches bots and people scouting for a DDoS, and it also catches a real
    // player behind a work tunnel. The most useful of the four and the one
    // most likely to annoy somebody honest.
    "BlockHosting": false,

    // Refuse anybody the service scores at or above this, 1 to 100. 0 is off.
    // Start at 90 if you want to try it, and watch your alert channel first.
    "MaxThreat": 0,

    // TRUE means I only tell you, I never refuse anybody. Leave this true for
    // a week before you set it false. You will be surprised who gets caught.
    "WarnOnly": true
  },

  // Looking an address up so you can see where a player is and whether the
  // connection is hiding something. Your key goes in geo.json, not here.
  "Geo": {
    // Off by default. Everything else in the plugin works without it. Bans on
    // an account, an address or a range all work with this off. What you lose
    // is country and company bans, the VPN flags, and the country report.
    "Enabled": false,

    // Ask for the VPN, proxy, Tor and threat flags as well as the location.
    // On ipgeolocation this makes each new address cost 3 credits instead of 1,
    // so a free 1000 a day key covers about 333 new players instead of 1000.
    // I print that sum in the log at startup using your own settings.
    "Security": false,

    // What to do about a player whose address I have never looked up, when you
    // have a country or company ban in place.
    //   false, the default: let them in, look it up, and remove them a second
    //          later if the answer says they are banned. First join gets
    //          through, every later one is refused at the door.
    //   true:  refuse them and ask them to try again in a moment, so nobody
    //          ever gets in. Correct, and it turns a slow service into a
    //          server nobody can join. Only use this if you know what it costs.
    "StrictGate": false,

    // How long I trust an answer before asking again, in days.
    "TtlDays": 30,

    // A hard ceiling on lookups a day, counted by me. Stops a join flood or a
    // bot sweep burning a month of credits in an hour. 0 means no ceiling.
    "MaxPerDay": 300,

    // Seconds between lookups. One at a time, always. A restart with 60 players
    // trickles instead of firing 60 web requests at once.
    "MinSecondsBetween": 1.0,

    // How many addresses I will hold waiting to be looked up.
    "QueueMax": 500
  },

  // Keeping somebody out of chat.
  "Mute": {
    // If you already run WarnSystem, leave this alone. I check for it at
    // startup and step aside, because two plugins muting people means your
    // staff never know which one did it.
    "Enabled": true,

    // What a mute does when nobody says otherwise.
    //   "chat"  their chat lines are dropped, their commands still work
    //   "all"   chat and commands both dropped
    //   "quiet" they see their own lines and nobody else does
    //
    // A word about "quiet". It is a real moderation tool: a loud player who
    // knows they are muted makes a new account inside five minutes, one who
    // does not know keeps talking to an empty room and gets bored. It is also
    // the kind of thing to use on purpose, not by accident, so it is not the
    // default and this comment says plainly what it does.
    "DefaultKind": "chat",

    // Repeat offences inside this many days climb the ladder below. Set it to 0
    // and every mute starts at the first rung again.
    "EscalateWindowDays": 30,

    // How long a mute lasts, in minutes, the first time, the second time, and
    // so on. The last one repeats forever. Used when you mute somebody without
    // naming a length yourself. 10080 is a week.
    "Ladder": [ 5, 30, 120, 1440, 10080 ]
  },

  // An IP address counts as personal data in the EU and the UK, and it is you
  // who holds it, not me. So these settings default to careful and everything
  // here actually happens. The retention lines below are real deletes.
  "Privacy": {
    // TRUE keeps the whole address so your staff can read it.
    //
    // FALSE keeps a salted hash plus the /24 and the company, and nothing else.
    // Everything still works in that mode: an exact address ban compares a hash
    // against a hash just fine, a range ban only needs the /24, and the reports
    // still read. The only thing you lose is being able to read an address on
    // screen. If that trade suits you, this is a genuinely usable mode and not
    // a token one. The salt is made once and kept in geo.json.
    "StoreFullIp": true,

    // Login rows older than this many days are deleted. Really deleted, once a
    // day, not hidden behind a flag. 0 means keep them forever, which is a
    // choice you are making on purpose.
    "KeepLoginDays": 90,

    // Same, for the address lookups I have cached.
    "KeepGeoDays": 365,

    // Above 0, an address is swapped for its hash after this many days while
    // the login row itself stays. A middle road between the two modes above.
    "HashAfterDays": 0,

    // A public Discord post shows 203.0.113.*** instead of the whole address.
    // The whole value only ever goes to AlertWebhookURL.
    "RedactInDiscord": true,

    // Same for the in game window.
    "RedactInPanel": true,

    // The one permission node that lets somebody read a whole address anywhere.
    // Give it to the people you would trust with your own.
    "SeeIpNode": "Checkpoint.SeeIp"
  },

  // Nothing on this list can ever be refused by any ban of any kind. Put
  // yourself on it before you ban a single range. I say so in the log at
  // startup while it is empty, and if you do lock yourself out anyway, run
  // Checkpoint.Open from RCON.
  "SafeList": {
    // Exact EOS ids. Yours goes here.
    "Eos": [],

    // Exact addresses. Your home line and your office, if you like.
    "Ips": [],

    // Whole ranges, written like 203.0.113.0/24.
    "Cidrs": [],

    // Anybody holding one of these permission nodes is safe. The tidiest
    // option, because it follows your staff group and you never touch this file
    // again when somebody joins or leaves the team.
    "Nodes": [ "Checkpoint.Immune" ]
  },

  // Noticing things and telling you, rather than acting on them.
  "Watch": {
    // Two accounts have to share a connection inside this many days for me to
    // call them linked.
    "LinkWindowDays": 30,

    // How many linked accounts to show in one report.
    "LinksShown": 8,

    // How many countries Checkpoint.Where lists.
    "CountriesShown": 10,

    // Tell your alert channel when a fresh account joins from a connection that
    // carries a ban. I only tell you. I never act on it unless you turned
    // Gate.AutoBanEvaders on.
    "AlertOnEvader": true,

    // Tell your alert channel when one account joins from two places too far
    // apart to be one person travelling. Usually a VPN being switched, and
    // sometimes two people sharing a login.
    "AlertOnOddTravel": true,

    // How fast is too fast, in kilometres an hour. 900 is roughly a passenger
    // jet, so anything above it is not somebody who got on a plane.
    "ImpossibleTravelKmH": 900.0,

    // Ignore hops shorter than this many kilometres. Stops a normal city to
    // city move from looking odd just because the clock was tight.
    "ImpossibleTravelMinKm": 500.0,

    // Printed at the bottom of every link report, every time. Say it in your
    // own words if you like, but please keep saying something, because a
    // household and an alt account leave exactly the same trail.
    "LinkCaveat": "One house, one flat share, a school or a mobile carrier all look exactly like this. A Weak line on its own means almost nothing."
  },

  // Player to player travel.
  "Travel": {
    // Turn this off and I am a moderation plugin only, with no travel commands
    // registered at all. If you already run TeleportRequest, I notice it at
    // startup and step aside on my own, because we both want /tpa.
    "Enabled": true,

    // Allow /tph, asking somebody to come to you. They still have to say yes.
    // Turn it off and travel only ever goes one way, towards the other person.
    "AllowSummon": true,

    // How long an ask sits there before I give up on it, in seconds.
    "RequestTimeoutSeconds": 45,

    // How long a player waits between travels, in seconds.
    "CooldownSeconds": 120,

    // How long the SAME TWO players wait before travelling to each other again,
    // in seconds. This is the one that stops two friends using each other as a
    // free taxi across the map all day. 0 turns it off.
    "PairCooldownSeconds": 300,

    // Most travels one player gets in a day. 0 means no limit.
    "MaxPerDay": 0,

    // Refuse a travel longer than this, in game units. -1 means any distance.
    // Roughly 100000 is a fair chunk of a map if you want to try a number.
    "MaxDistance": -1,

    // Hold the mover still for this many seconds before they go. If anything
    // hits either of them, or they walk off, I stop and hand their points back.
    // 0 makes travel instant, which players like and raiders like more.
    "WarmupSeconds": 5,

    // How far the mover may drift during the warmup before I call it off.
    "WarmupMoveTolerance": 300.0,

    // Refuse a travel when either player is on a dino. On by default, because
    // a dino left behind mid warp is a support ticket.
    "CheckForDino": true,

    // Stop the warmup if the mover is dropping. Catches somebody using travel
    // to cancel a fall.
    "BlockWhileFalling": true,

    // How far they have to drop in one second for me to call it falling.
    "FallingDrop": 400.0,

    // Points each travel costs the asker, charged when the other player says
    // yes and handed straight back if the travel then fails for any reason.
    // 0 makes travel free. Needs ArkShop or WShop, and if neither is installed
    // travel is free and I say so once in the log rather than breaking.
    "PointCost": 0,

    // Refusals in a row that earn a player a time out. A player who tries nine
    // times to warp into a raid is telling you something, and this is where I
    // stop being polite and post to your alert channel.
    "AbuseStrikes": 5,

    // The window those refusals have to land in, in minutes.
    "AbuseWindowMinutes": 10,

    // How long the time out lasts, in seconds.
    "AbusePenaltySeconds": 900
  },

  // When travel is shut. These are the settings that separate a travel plugin
  // people keep from one they uninstall after their first bad raid.
  "Gates": {
    // Nobody travels for this many seconds after either player was in a fight.
    "CombatSeconds": 20,

    // Nobody travels into or out of a tribe that is being raided, or that is
    // doing the raiding, for this many seconds after the last hit on a base.
    //
    // This is the important one. Without it, twelve defenders warp in one after
    // another the moment a raid starts, because a travel request is faster than
    // a bird. 300 is five minutes and is a sensible place to start. Set it to 0
    // only if your server has no raiding at all.
    "RaidSeconds": 300,

    // On a PvE server the two gates above are pointless, so I switch them off
    // and say so at startup. I read whether you are PvE from the game itself.
    "RelaxOnPve": true
  },

  // How I turn what somebody typed into one exact player. Every command that
  // takes a player name uses this, in chat and on RCON both.
  //
  // It already handles: the survivor name, the account name, a bare EOS id,
  // char: name: tribe: id: and eos: prefixes, a quoted name, #2 to pick off the
  // list I just showed, accents, Cyrillic and Greek letters that look Latin,
  // fullwidth and circled letters, xX_tags_Xx, and leet like 5n4k3.
  "Targeting": {
    // Match the survivor name, the one over their head. Players type this one.
    "MatchCharacterName": true,

    // Match the account name from Steam, Xbox or PlayStation.
    "MatchPlatformName": true,

    // Match a tribe name, then let you pick a member. Scored below a person, so
    // a player called Wolves always beats a tribe called Wolves.
    "MatchTribeName": true,

    // Match a name they used to wear. Stops a rename shaking off a ban.
    "MatchOldNames": true,

    // Let staff commands find somebody who is not online. On, because banning
    // an offline player is the normal case. Travel always needs them online.
    "AllowOffline": true,

    // How far back to look for an offline player, in days.
    "OfflineDays": 30,

    // Allow for typing mistakes. Turn it off and only real names match.
    "FuzzyTypos": true,

    // Most mistakes allowed in a longer name. Short names get fewer on their
    // own, so Dob can find Bob without Dob finding Cat.
    "MaxTypos": 2,

    // Do not allow mistakes in anything shorter than this many letters.
    "MinTypoLength": 3,

    // How many to show when more than one player matches. When two are equally
    // good I never guess, I show the list and you answer with a number.
    "ShowChoices": 5,

    // How long that numbered list stays good for, in seconds.
    "PickSeconds": 90,

    // How long "last" reaches back for whoever last asked you to travel, in
    // minutes.
    "RecentMinutes": 10
  },

  // Who is allowed to do what. Needs the free Permissions plugin. Without it,
  // staff chat commands say no to everybody and the console and RCON still
  // work, which is where the real power is anyway.
  "Permissions": {
    "Enabled": true,

    // Players need this to use travel at all. With Permissions missing this
    // one fails OPEN, so travel keeps working on a server that does not run it.
    "TravelNode": "Checkpoint.Travel",

    // Staff nodes. These all fail CLOSED, so a missing Permissions means no.
    "WhoNode": "Checkpoint.Who",
    "BanNode": "Checkpoint.Ban",
    "MuteNode": "Checkpoint.Mute",
    "KickNode": "Checkpoint.Kick",
    "AltsNode": "Checkpoint.Alts",

    // A shorter travel cooldown for people holding a node. Add as many lines as
    // you like. The shortest one they qualify for wins.
    "FasterFor": {
      "Checkpoint.Vip": 30
    }
  },

  // The points shop, only used if you set Travel.PointCost above 0.
  "ArkShop": {
    "Enabled": true,

    // "Auto" takes ArkShop if it is running, then WShop. Name one on purpose if
    // you run both, which almost nobody does.
    "Provider": "Auto"
  },

  // Where my records live. This one is worth reading properly, because it is
  // the difference between a ban that covers one map and a ban that covers all
  // of them.
  "Database": {
    // FALSE uses SQLite, a single file in my data folder, with nothing to set
    // up. Perfect for one server.
    //
    // TRUE uses MySQL, and then every map pointed at the same database shares
    // one ban list, one set of records and one view of who is linked to whom.
    // On a cluster that is the whole point. Set Gate.ClusterWide to true as
    // well, or a ban still only covers the map it was placed on.
    "UseMySQL": false,

    // Where to put the SQLite file. Leave it empty and I use my own data
    // folder, which is what you want. It is the folder to copy if you ever
    // want a backup of every ban you have placed.
    "SQLiteDatabasePath": "",

    // The front of all seven of my table names. Change it if something else is
    // already using these names in your database.
    "TablePrefix": "checkpoint",

    // MySQL only, all ignored on SQLite.
    "Host": "127.0.0.1",
    "Port": 3306,
    "User": "",
    "Password": "",
    "Database": "",

    // Leave these two alone unless your host told you otherwise. -1 and empty
    // mean use whatever the server and the client agree on.
    "MysqlSSLMode": -1,
    "MysqlTLSVersion": ""
  },

  // On screen messages through the free ASA API Utils mod. The mod is a nice
  // to have and never required. Without it I talk in chat instead and say so
  // once in the log.
  "ApiUtilsMod": {
    "Enabled": true,

    // The box behind the words: red, green, blue, and how solid, each 0.0 to 1.0.
    // The last number is the one to change. 0.55 is a soft dark box.
    "BackdropColor": [ 0.0, 0.0, 0.0, 0.55 ],

    // Where on screen: "Left", "Center" or "Right".
    "ScreenPosition": "Center",

    // How the words sit in the box: "Left", "Center" or "Right".
    "TextAlign": "Center",

    // Bigger than 1.0 is bigger text.
    "TextScale": 1.0,

    // How long a message stays up, in seconds.
    "MessageSeconds": 6.0,

    // Also put the same words in the chat log, so a player can scroll back to
    // a warmup countdown or a mute notice they missed. This does mean two
    // messages per send, which is fine.
    "AlsoShowInChat": true
  },

  // The game gives me level names like TheIsland_WP, which no player should
  // ever read.
  "MapName": {
    // Tidy it up into The Island. Turn it off to see the raw name.
    "Pretty": true,

    // Or write your own, for a map I get wrong or a modded one.
    // Example: { "Svartalfheim_WP": "Svartalfheim" }
    "Overrides": {}
  },

  // The in game window from the NordBots UI mod. Players get a Travel pane with
  // buttons for who is waiting on them, and staff with the right nodes get an
  // arrivals pane and a bans pane. A button press runs the exact same command
  // the chat version runs, with the same permission check, so the window is
  // never a way around anything.
  "Panel": {
    // Off means I never open a window. Every chat command still works.
    "Enabled": true,

    // Rows in one pane before it pages.
    "RowsPerPage": 8,

    // How many rows a top list shows.
    "TopCount": 10,

    // Leave these three alone unless the mod tells you to change them.
    "BuffTag": "NordBotsUIBuff",
    "BuffPath": "NordBotsUI/Buff_NordBotsUI",
    "SingletonPath": "Blueprint'/NordBotsUI/NordBotsUI_Singleton.NordBotsUI_Singleton'",

    // Wait for the mod to say hello before I send it anything. Off is fine and
    // is what almost everybody wants.
    "RequireHandshake": false
  }
}