Files
CoreProtect/lang/en.yml
T
d5db22c23e Entity radius purge (#1030)
* Fixed world purges leaving orphaned entity data

co_entity has no world column, so /co purge r:#world deleted the kill
rows in co_block but kept every co_entity row. Those blobs became
orphans that no later purge removed.

- SQLite: copy only the co_entity rows that a retained kill row still
  references. This also drops orphans left by earlier purges.
- MySQL/DuckDB: delete the co_entity rows of the kill rows a world purge
  removes, before co_block is purged. MySQL uses a join so MariaDB and
  MySQL 5.7 do not run a dependent subquery. Global purges keep the
  cheaper time-based delete, which is equivalent. If MySQL stops between
  the two deletes, running the same purge again removes the remaining
  kill rows.

Player kills use the kill action with type 0 and a user id in data, so
they are never treated as co_entity references.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdEuKbjcVoVinVQJq4te1f

* Fixed SQLite purges with world and block filters purging other tables

On SQLite, /co purge r:#world i:<block> built the retain condition for
world-scoped tables without checking the block restriction, so it purged
co_container, co_chat and the other world-scoped tables in that world
although a block restriction should leave them untouched. The
entity_container/entity_interaction branch and the MySQL path already
check it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdEuKbjcVoVinVQJq4te1f

* Fixed console purges with a radius purging all worlds

/co purge rejects a numeric radius, but the check only saw the radius
when the sender had a location. From the console, /co purge t:30d r:50
parsed no radius and no world, so it ran as a server-wide purge. The
radius is now also parsed against a placeholder location, so it is
rejected for every sender. r:#world is unaffected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdEuKbjcVoVinVQJq4te1f

* Added orphaned entity data cleanup to MySQL #optimize purges

MySQL deletes in place, so co_entity rows orphaned by earlier world
purges stay until something removes them. With #optimize, delete every
co_entity row that no kill row references, through a temporary table of
referenced ids (avoids an anti-join on the unindexed co_block.data), then
let OPTIMIZE reclaim the space. Failures are reported like the table
loop, so the entity_spawn link cleanup still runs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdEuKbjcVoVinVQJq4te1f

* Moved purge conditions into PurgeFilter

PurgeFilter now builds the purge condition for every table, and the
SQLite copy, the SQLite recovery path and the MySQL/DuckDB delete all use
it instead of three hand-built copies. Behavior is unchanged; the block
restriction check that the previous commit added to the SQLite copy is
part of the shared condition.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdEuKbjcVoVinVQJq4te1f

* Added entity kill filters to purge command

/co purge rejected entity types and actions, so mob farm kill logs could
only be removed together with all other data. New arguments on SQLite,
MySQL and DuckDB:

- a:kill purges only entity kill rows.
- i:<entity> purges kills of those entity types; it can be combined with
  block types.
- e:<entity> keeps kills of those entity types while purging the rest.

Each purged kill also removes its co_entity row. a:kill with block types,
entity types in both i: and e:, e: with only block types in i:,
non-entity exclusions and entity filters on ClickHouse are rejected. Any
a: value other than a kill alias is rejected instead of falling through
to an unrestricted purge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdEuKbjcVoVinVQJq4te1f

* Added radius support to purge command

/co purge rejected any numeric radius, so kills of one entity type could
only be purged across a whole world. A radius is now accepted when the
purge is restricted to co_block rows with i: or a:kill, for example
/co purge t:30d r:50 i:zombie. r:50x10 also limits the height.

The radius becomes an x/y/z range in the co_block condition. co_entity
rows follow the purged kill rows, so no entity data is orphaned, and the
(wid,x,z,time) index already covers the range. Other tables are left
untouched, as with any restricted purge.

Rejected: a radius without i: or a:kill, WorldEdit selections, radius
purges on ClickHouse, and a numeric radius from the console (it has no
location, as in the console radius fix merged into this branch).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PdEuKbjcVoVinVQJq4te1f

* Made MySQL entity data purges safe against concurrent writers

The #optimize orphan sweep snapshots the co_entity ids that kill rows
reference, then deletes every row missing from the snapshot. Another
installation sharing the database could commit a kill between the two
statements and lose its entity data. The sweep now only deletes rows
inside the purge time range. A kill always writes its co_entity row with
the current time, and a purge range ends at least 24 hours ago, so a
concurrent kill never matches.

A world purge deletes the entity data of the purged kills and
then the kill rows. On MySQL a failure or cancellation between the two
left kept kill rows without their rollback data. Both deletes now run in
one transaction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Limited SQLite entity data cleanup to the purge time range

A SQLite purge dropped every co_entity row no kill referenced, including
rows newer than the purge range, and counted them as deleted. It now only
removes unreferenced rows inside the range, like the MySQL #optimize sweep.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Rejected purge include and exclude lists without a value

/co purge t:30d e: passed validation, parsed to no exclusions, and ran
as an unrestricted time purge. e:, and e:,,, did the same, as did an
e: at the end of the command and an empty i:. The argument check now
follows each include or exclude list across its continuation tokens and
rejects a list that ends without a value. Space-separated lists such as
e:zombie, villager still work.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Matched purge entity filters to kills logged under renamed types

Bukkit resolves a legacy name such as zombie_pigman to the renamed type,
so the filter only matched the id of the new name. e:zombie_pigman then
purged the old kills it was meant to keep, and i:zombie_pigman missed
them. The filter now covers every entity map id that resolves to the type.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Rejected purges with more than one radius argument

/co purge t:30d r:50 r:#world_nether i:zombie ignored the explicit world
and purged around the player in their current world. Two r: arguments
always conflict, so the second one is now rejected before the purge
starts, whether it is a world, #global or another radius.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Applied max-radius to radius purges

A radius purge accepted any value. A radius past the int range saturated,
the area overflowed, and the purge reported success with nothing deleted.
It now stops at max-radius like lookups and rollbacks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Checked radius arguments inside purge include and exclude lists

/co purge t:30d i:zombie, r:50 r:#world_nether passed the second-radius
check: the validator took r:50 as a value of the include list, then saw
r:#world_nether as the only radius. The radius and world parsers read
both. A list now continues only with plain or minecraft: namespaced
values, so a radius after a trailing comma is counted and the second one
is rejected. This is the same change as 39deec3 on entity-kill-purge-filters.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LFQuzYmYun57wJi2a5mqkM

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: TonyJamesStark <tonyjamesstark1@gmail.com>
2026-10-05 17:46:22 -06:00

240 lines
13 KiB
YAML

# CoreProtect Language File (en)
ACTION_NOT_SUPPORTED: "That action is not supported by the command."
AMOUNT_BLOCK: "{0} {block|blocks}"
AMOUNT_CHUNK: "{0} {chunk|chunks}"
AMOUNT_ENTITY: "{0} {entity|entities}"
AMOUNT_ITEM: "{0} {item|items}"
API_TEST: "API test successful."
CACHE_ERROR: "WARNING: Error while validating {0} cache."
CACHE_RELOAD: "Forcing reload of {mapping|world} caches from database."
CHECK_CONFIG: "Please check config.yml"
COMMAND_CONSOLE: "Please run the command from the console."
COMMAND_NOT_FOUND: "Command \"{0}\" not found."
COMMAND_THROTTLED: "Please wait a moment and try again."
CONSUMER_ERROR: "Consumer queue processing already {paused|resumed}."
CONSUMER_TOGGLED: "Consumer queue processing has been {paused|resumed}."
CONTAINER_HEADER: "Container Transactions"
CPU_CORES: "CPU cores."
DATABASE_BUSY: "Database busy. Please try again later."
DATABASE_FALLBACK: "Unable to load {0}. Using {1}; config.yml updated."
DATABASE_INDEX_ERROR: "Unable to validate database indexes."
DATABASE_LOCKED_1: "Database locked. Waiting up to 15 seconds..."
DATABASE_LOCKED_2: "Database is already in use. Please try again."
DATABASE_LOCKED_3: "To disable database locking, set \"database-lock: false\"."
DATABASE_LOCKED_4: "Disabling database locking can result in data corruption."
DATABASE_PERSISTENCE_HALTED: "Database writes halted. Please restart the server."
DATABASE_QUEUE_LOSS: "Queued data will be lost when the server stops."
DATABASE_RECOVERY_FAILED: "Database recovery failed after {0} attempts."
DATABASE_RECOVERY_STARTED: "Database became unavailable. Attempting database recovery."
DATABASE_RECOVERY_SUCCESS: "Database recovery completed. Queued writes will resume."
DATABASE_TYPE_OVERRIDE: "Option \"database-type\" overrides \"use-mysql\"."
DATABASE_UNREACHABLE: "Database is unreachable. Discarding data and shutting down."
DEVELOPMENT_BRANCH: "Development branch detected, skipping patch scripts."
DIRT_BLOCK: "Placed a temporary safety block under you."
DISABLE_SUCCESS: "Success! Disabled {0}"
DONATION_KEY_REQUIRED: "A valid donation key is required for that command."
ENABLE_FAILED: "{0} was unable to start."
ENABLE_SUCCESS: "{0} has been successfully enabled!"
ENJOY_COREPROTECT: "Enjoy {0}? Join our Discord!"
FINISHING_CONVERSION: "Finishing up data conversion. Please wait..."
FINISHING_LOGGING: "Finishing up data logging. Please wait..."
FIRST_VERSION: "Initial DB: {0}"
GLOBAL_LOOKUP: "Don't specify a radius to do a global lookup."
GLOBAL_ROLLBACK: "Use \"{0}\" to do a global {rollback|restore}"
HELP_ACTION_1: "Restrict the lookup to a certain action."
HELP_ACTION_2: "Examples: [a:block], [a:+block], [a:-block] [a:click], [a:container], [a:inventory], [a:item], [a:kill], [a:spawn], [a:chat], [a:command], [a:sign], [a:session], [a:username]"
HELP_COMMAND: "Display more info for that command."
HELP_EXCLUDE_1: "Exclude blocks/users."
HELP_EXCLUDE_2: "Examples: [e:stone], [e:Notch], [e:stone,Notch]"
HELP_FILTER_1: "Filter chat, command, or sign text."
HELP_FILTER_2: "Examples: [a:command f:/co], [a:sign f:Shop]"
HELP_HEADER: "{0} Help"
HELP_INCLUDE_1: "Include specific blocks/entities."
HELP_INCLUDE_2: "Examples: [i:stone], [i:zombie], [i:stone,wood,bedrock]"
HELP_INSPECT_1: "With the inspector enabled, you can do the following:"
HELP_INSPECT_2: "Left-click a block to see who placed that block."
HELP_INSPECT_3: "Right-click a block to see what adjacent block was broken."
HELP_INSPECT_4: "Place a block to see what block was broken at that location."
HELP_INSPECT_5: "Place a block in liquid (etc) to see who placed it."
HELP_INSPECT_6: "Right-click on a door, chest, etc, to see who last used it."
HELP_INSPECT_7: "Tip: You can use just \"/co i\" for quicker access."
HELP_INSPECT_COMMAND: "Turns the block inspector on or off."
HELP_LIST: "Displays a list of all commands."
HELP_LOOKUP_1: "Command shortcut."
HELP_LOOKUP_2: "Use after inspecting a block to view logs."
HELP_LOOKUP_COMMAND: "Advanced block data lookup."
HELP_NO_INFO: "Information for command \"{0}\" not found."
HELP_PARAMETER: "Please see \"{0}\" for detailed parameter info."
HELP_PARAMS_1: "Perform the {lookup|rollback|restore}."
HELP_PARAMS_2: "Specify the user(s) to {lookup|rollback|restore}."
HELP_PARAMS_3: "Specify the amount of time to {lookup|rollback|restore}."
HELP_PARAMS_4: "Specify a radius area to limit the {lookup|rollback|restore} to."
HELP_PARAMS_5: "Restrict the {lookup|rollback|restore} to a certain action."
HELP_PARAMS_6: "Include specific blocks/entities in the {lookup|rollback|restore}."
HELP_PARAMS_7: "Exclude blocks/users from the {lookup|rollback|restore}."
HELP_PURGE_1: "Delete data older than specified time."
HELP_PURGE_2: "For example, \"{0}\" will delete all data older than one month, and only keep the last 30 days of data."
HELP_PURGE_3: "Specify the amount of time to purge."
HELP_PURGE_4: "Specify a world or radius to limit the purge to."
HELP_PURGE_5: "Include specific blocks or entity kills in the purge."
HELP_PURGE_6: "Keep entity kills of these types."
HELP_PURGE_7: "Only purge entity kills."
HELP_PURGE_COMMAND: "Delete old block data."
HELP_RADIUS_1: "Specify a radius area."
HELP_RADIUS_2: "Examples: [r:10] (Only make changes within 10 blocks of you)"
HELP_RELOAD_COMMAND: "Reloads the configuration file."
HELP_RESTORE_COMMAND: "Restore block data."
HELP_ROLLBACK_COMMAND: "Rollback block data."
HELP_STATUS: "View the plugin status and version information."
HELP_STATUS_COMMAND: "Displays the plugin status."
HELP_TELEPORT: "Teleport to a location."
HELP_TIME_1: "Specify the amount of time to lookup."
HELP_TIME_2: "Examples: [t:2w,5d,7h,2m,10s], [t:5d2h], [t:2.50h]"
HELP_USER_1: "Specify the user(s) to lookup."
HELP_USER_2: "Examples: [u:Notch], [u:Notch,#enderman]"
INCOMPATIBLE_ACTION: "\"{0}\" can't be used with that action."
INSPECTOR_ERROR: "Inspector already {enabled|disabled}."
INSPECTOR_TOGGLED: "Inspector now {enabled|disabled}."
INTEGRATION_ERROR: "Unable to {initialize|disable} {0} logging."
INTEGRATION_SUCCESS: "{0} logging successfully {initialized|disabled}."
INTEGRATION_VERSION: "Invalid {0} version found."
INTERACTIONS_HEADER: "Player Interactions"
INVALID_ACTION: "That is not a valid action."
INVALID_BRANCH_1: "Invalid plugin version (branch has not been set)."
INVALID_BRANCH_2: "To continue, set project branch to \"development\"."
INVALID_BRANCH_3: "Running development code may result in data corruption."
INVALID_CONTAINER: "Please inspect a valid container first."
INVALID_DONATION_KEY: "Invalid donation key."
INVALID_INCLUDE: "\"{0}\" is an invalid block/entity name."
INVALID_INCLUDE_COMBO: "That is an invalid block/entity combination."
INVALID_ITEM_ID: "Please enter a valid item id."
INVALID_PARAMETER: "\"{0}\" is not a supported parameter."
INVALID_RADIUS: "Please enter a valid radius."
INVALID_SELECTION: "{0} selection not found."
INVALID_USERNAME: "\"{0}\" is an invalid username."
INVALID_WORLD: "Please specify a valid world."
LATEST_VERSION: "Latest Version: {0}"
LINK_DISCORD: "Discord: {0}"
LINK_DOWNLOAD: "Download: {0}"
LINK_PATREON: "Patreon: {0}"
LINK_WIKI_BLOCK: "Block Names: {0}"
LINK_WIKI_ENTITY: "Entity Names: {0}"
LOGGING_ITEMS: "{0} items left to log. Please wait..."
LOGGING_TIME_LIMIT: "Logging time limit reached. Discarding data and shutting down."
LOOKUP_BLOCK: "{0} {placed|broke} {1}."
LOOKUP_CONTAINER: "{0} {added|removed} {1} {2}."
LOOKUP_ENTITY_INTERACTION: "{0} {clicked|sheared|leashed|unleashed} {1}."
LOOKUP_ENTITY_INTERACTION_ORIGIN: "Origin location"
LOOKUP_ENTITY_ORIGIN: "Spawn location"
LOOKUP_ENTITY_SPAWN: "{0} spawned {1}."
LOOKUP_HEADER: "{0} Lookup Results"
LOOKUP_INTERACTION: "{0} {clicked|killed} {1}."
LOOKUP_ITEM: "{0} {picked up|dropped} {1} {2}."
LOOKUP_LOGIN: "{0} logged {in|out}."
LOOKUP_PAGE: "Page {0}"
LOOKUP_PROJECTILE: "{0} {threw|shot} {1} {2}."
LOOKUP_ROWS_FOUND: "{0} {row|rows} found."
LOOKUP_SEARCHING: "Lookup searching. Please wait..."
LOOKUP_STORAGE: "{0} {deposited|withdrew} {1} {2}."
LOOKUP_TIME: "{0} ago"
LOOKUP_USERNAME: "{0} logged in as {1}."
MAXIMUM_PURGE_RADIUS: "The maximum purge radius is {0}."
MAXIMUM_RADIUS: "The maximum {lookup|rollback|restore} radius is {0}."
MESSAGE_FILTER_TOO_SHORT: "Minimum message filter length is {0} characters."
MISSING_ACTION_USER: "To use that action, please specify a user."
MISSING_LOOKUP_TIME: "Please specify the amount of time to {lookup|rollback|restore}."
MISSING_LOOKUP_USER: "Please specify a user or {block|radius} to lookup."
MISSING_PARAMETERS: "Please use \"{0}\"."
MISSING_ROLLBACK_RADIUS: "You did not specify a {rollback|restore} radius."
MISSING_ROLLBACK_USER: "You did not specify a {rollback|restore} user."
MYSQL_UNAVAILABLE: "Unable to connect to MySQL server."
NETWORK_CONNECTION: "Connection by {0} {successful|failed}. Using {1} {2}."
NETWORK_TEST: "Network test data has been successful sent."
NO_DATA: "No data found at {0}."
NO_DATA_LOCATION: "No {data|transactions|interactions|messages} found at this location."
NO_PERMISSION: "You do not have permission to do that."
NO_RESULTS: "No results found."
NO_RESULTS_PAGE: "No {results|data} found for that page."
NO_ROLLBACK: "No {pending|previous} rollback/restore found."
PATCH_INTERRUPTED: "Upgrade interrupted. Will try again on restart."
PATCH_OUTDATED_1: "Unable to upgrade databases older than {0}."
PATCH_OUTDATED_2: "Please upgrade with a supported version of CoreProtect."
PATCH_PROCESSING: "Processing new data. Please wait..."
PATCH_SKIP_UPDATE: "Skipping {table|index} {update|creation|removal} on {0}."
PATCH_STARTED: "Performing {0} upgrade. Please wait..."
PATCH_SUCCESS: "Successfully upgraded to {0}."
PATCH_TABLE_COMPLETED: "Successfully updated {0} table."
PATCH_TABLE_STARTED: "Updating {0} table. Please wait..."
PATCH_UPGRADING: "Database upgrade in progress. Please wait..."
PLEASE_SELECT: "Please select: \"{0}\" or \"{1}\"."
PREVIEW_CANCELLED: "Preview cancelled."
PREVIEW_CANCELLING: "Cancelling preview..."
PREVIEW_IN_GAME: "You can only preview rollbacks in-game."
PREVIEW_TRANSACTION: "You can't preview {container|inventory} transactions."
PRIMARY_THREAD_ERROR: "That API method can't be used on the primary thread."
PURGE_ABORTED: "Purge failed. Database may be corrupt."
PURGE_ERROR: "Unable to process {0} data!"
PURGE_FAILED: "Purge failed. Please try again later."
PURGE_IN_PROGRESS: "Purge in progress. Please try again later."
PURGE_MINIMUM_TIME: "You can only purge data older than {0} {days|hours}."
PURGE_NOTICE_1: "Please note that this may take some time."
PURGE_NOTICE_2: "Do not restart your server until completed."
PURGE_OPTIMIZING: "Optimizing database. Please wait..."
PURGE_PROCESSING: "Processing {0} data..."
PURGE_REPAIRING: "Attempting to repair. This may take some time..."
PURGE_ROWS: "{0} {row|rows} of data deleted."
PURGE_STARTED: "Data purge started on \"{0}\"."
PURGE_SUCCESS: "Data purge successful."
RAM_STATS: "{0}GB / {1}GB RAM"
RELOAD_FAILED: "Database reload failed. Please try again."
RELOAD_STARTED: "Reloading configuration - please wait."
RELOAD_SUCCESS: "Configuration successfully reloaded."
ROLLBACK_ABORTED: "Rollback or restore aborted."
ROLLBACK_CHUNKS_FOUND: "Found {0} {chunk|chunks} to modify."
ROLLBACK_CHUNKS_MODIFIED: "Modified {0}/{1} {chunk|chunks}."
ROLLBACK_COMPLETED: "{Rollback|Restore|Preview} completed for \"{0}\"."
ROLLBACK_EXCLUDED_USERS: "Excluded {user|users}: \"{0}\"."
ROLLBACK_INCLUDE: "{Included|Excluded} {block|entity|target} {type|types}: \"{0}\"."
ROLLBACK_IN_PROGRESS: "A rollback/restore is already in progress."
ROLLBACK_LENGTH: "Time taken: {0} {second|seconds}."
ROLLBACK_MODIFIED: "{Modified|Modifying} {0}."
ROLLBACK_RADIUS: "Radius: {0} {block|blocks}."
ROLLBACK_SELECTION: "Radius set to \"{0}\"."
ROLLBACK_STARTED: "{Rollback|Restore|Preview} started on \"{0}\"."
ROLLBACK_TIME: "Time range: {0}."
ROLLBACK_WORLD_ACTION: "Restricted to {world|action} \"{0}\"."
SIGN_HEADER: "Sign Messages"
STATUS_AUTO_PURGE: "Cleanup: {0} {row|rows} auto purged since restart."
STATUS_CONSUMER: "Consumer: {0} {item|items} in queue."
STATUS_DATABASE: "Database: Using {0}."
STATUS_DATABASE_STATE: "({writes halted|unreachable})"
STATUS_INTEGRATION: "{0}: Integration {enabled|disabled}."
STATUS_LICENSE: "License: {0}"
STATUS_SYSTEM: "System: {0}"
STATUS_VERSION: "Version: {0}"
TELEPORTED: "Teleported to {0}."
TELEPORTED_SAFETY: "Teleported you to safety."
TELEPORT_PLAYERS: "Teleport command can only be used by players."
TIME_DAYS: "{0} {day|days}"
TIME_HOURS: "{0} {hour|hours}"
TIME_MINUTES: "{0} {minute|minutes}"
TIME_MONTHS: "{0} {month|months}"
TIME_SECONDS: "{0} {second|seconds}"
TIME_UNITS: "{/m|/h|/d}"
TIME_WEEKS: "{0} {week|weeks}"
TIME_YEARS: "{0} {year|years}"
UPDATE_ERROR: "An error occurred while checking for updates."
UPDATE_HEADER: "{0} Update"
UPDATE_NOTICE: "Notice: {0} is now available."
UPGRADE_IN_PROGRESS: "Upgrade in progress. Please try again later."
USER_NOT_FOUND: "User \"{0}\" not found."
USER_OFFLINE: "The user \"{0}\" is not online."
USING_DATABASE: "Using {0} for data storage."
USING_MYSQL: "Using MySQL for data storage."
USING_SQLITE: "Using SQLite for data storage."
VALID_DONATION_KEY: "Valid donation key."
VERSION_INCOMPATIBLE: "{0} {1} is not supported."
VERSION_NOTICE: "Version {0} is now available."
VERSION_REQUIRED: "{0} {1} or higher is required."
WORLD_NOT_FOUND: "World \"{0}\" not found."