Major Challenge: Renumbering the geo_patch TableOne approach to removing a group of changes to terrain is to delete them from the geo_patch table. Assuming deletion is done correctly, the geo_patch table will now have gaps in its ID and Version sequences that would never be present in the normal operation in the game.
Here is Version 0.1 of database procedures to renumber the ID and Version columns of geo_patch.
These are currently being tested. Use at your own risk and backup first!
Preliminary: Checking for Gaps in SequencesThere are two sequences maintained in geo_patch:
- the ID field, which is a unique number for every row in the table
- Version, which is a separate sequence for each TerID and may repeat with multiple ChangeIndex values for a single Version.
Query geo_data for gaps in ID:
- Code: Select all
SELECT a.id+1 AS start, MIN(b.id) - 1 AS end
FROM geo_patch AS a, geo_patch AS b
WHERE a.id < b.id
GROUP BY a.id
HAVING start < MIN(b.id);
Query geo_data for gaps in Version for a particular TerID. (446 in this example.)
- Code: Select all
SELECT a.Version+1 AS start, MIN(b.Version) - 1 AS end
FROM geo_patch AS a, geo_patch AS b
WHERE a.Version < b.Version
AND a.TerID = 446
AND b.TerID = 446
GROUP BY a.Version
HAVING start < MIN(b.Version);
Procedures to Collapse Gaps in geo_dataVersion:
This procedure runs very slowly unless indices are added to help the database deal with indexing by TerID and Version. Adding them seems harmless, but dropping them afterward might be a good idea.
- Code: Select all
DROP INDEX geo_patch_Version ON geo_patch;
DROP INDEX geo_patch_TerID_Version ON geo_patch;
CREATE INDEX geo_patch_Version ON geo_patch (Version);
CREATE INDEX geo_patch_TerID_Version ON geo_patch (TerID, Version);
Procedure to collapse gaps in Version for a given TerID:
- Code: Select all
-- p_renumberGeoPatchVersion
-- Procedure to collapse gaps in Version that may exist in the geo_patch
-- table following deletions.
DROP PROCEDURE IF EXISTS p_renumberGeoPatchVersion;
DELIMITER $$
CREATE PROCEDURE p_renumberGeoPatchVersion(in_TerID INT UNSIGNED)
BEGIN
DECLARE ii INT UNSIGNED;
DECLARE maxVersion INT UNSIGNED;
DECLARE currCount INT UNSIGNED;
DECLARE next INT UNSIGNED;
SELECT 'Renumbering Version';
-- Version can start greater than 0. Trust that the lowest Version for this TerID is correct.
SET ii = (SELECT MIN(Version) FROM geo_patch WHERE TerID = in_TerID);
SET maxVersion = (SELECT ii + COUNT(DISTINCT(Version)) - 1 FROM geo_patch WHERE TerID = in_TerID);
WHILE ii <= maxVersion DO
SET currCount = (SELECT COUNT(*) FROM geo_patch WHERE TerID = in_TerID AND Version = ii);
IF currCount = 0 THEN
SET next = (SELECT MIN(VERSION) FROM geo_patch WHERE TerID = in_TerID AND Version > ii);
-- SELECT ii, currCount, next
UPDATE geo_patch
SET Version = ii
WHERE Version = next;
-- SET maxVersion = MaxVersion - 1
END IF;
SET ii = ii + 1;
-- Loops are slow in databases. Print out progress to reduce anxiety over a long-running procedure.
IF ii % 100 = 0 THEN
SELECT ii, currCount;
END IF;
END WHILE;
SELECT maxVersion;
UPDATE terrain_blocks SET GeoVersion = ( SELECT MAX(Version) FROM geo_patch WHERE TerID = in_TerID) WHERE ID = in_TerID;
END$$
DELIMITER ;
Procedure to collapse gaps in ID:
- Code: Select all
-- p_renumberGeoPatchID
-- Procedure to collapse gaps in ID that may exist in the geo_patch
-- table following deletions.
DROP PROCEDURE IF EXISTS p_renumberGeoPatchID;
DELIMITER $$
CREATE PROCEDURE p_renumberGeoPatchID()
BEGIN
DECLARE ii INT UNSIGNED;
DECLARE maxID INT UNSIGNED;
DECLARE currCount INT UNSIGNED;
DECLARE next INT UNSIGNED;
SELECT 'Renumbering ID';
-- ID can start greater than 0. Trust that the lowest ID.
SET ii = (SELECT MIN(ID) FROM geo_patch);
SET maxID = (SELECT ii + COUNT(*) - 1 FROM geo_patch);
WHILE ii <= maxID DO
SET currCount = (SELECT COUNT(*) FROM geo_patch WHERE ID = ii);
IF currCount = 0 THEN
SET next = (SELECT MIN(ID) FROM geo_patch WHERE ID > ii);
-- SELECT ii, currCount, next
UPDATE geo_patch
SET ID = ii
WHERE ID = next;
-- SET maxVersion = MaxVersion - 1
END IF;
SET ii = ii + 1;
-- Loops are slow in databases. Print out progress to reduce anxiety over a long-running procedure.
IF ii % 100 = 0 THEN
SELECT ii, currCount;
END IF;
END WHILE;
SELECT maxID;
END$$
DELIMITER ;
Running the ProceduresRunning the procedures for the TerID being edited is pretty simple. (Example for 446)
- Code: Select all
START TRANSACTION;
-- do something
CALL p_renumberGeoPatchVersion(446);
CALL p_renumberGeoPatchID();
COMMIT; -- Or ROLLBACK, if something went wrong
Uh-oh! It still needs caching cleanup!Clients keep a cache of the Version of each TerID. If you try to connect to the modified server, it will kick you because your client (correctly) thinks it has a newer version for the terrain.
This APPEARS to be mediated/maintained by a
CRC value in the terrain_blocks table, that might be "fixed" by deleting it.
Basically, go back and delete all the CRC values for the TerID you just modified. (ID column on terrain_blocks).
e.g.
- Code: Select all
UPDATE terrain_blocks SET CachedGeoVersion=NULL, CachedTerCRC=NULL, CachedServerGeoIdxCRC=NULL, CachedServerGeoDatCRC=NULL, CachedClientGeoIdxCRC=NULL, CachedClientGeoDatCRC=NULL, PackedTerCRC=NULL, PackedClientGeoIdxCRC=NULL, PackedClientGeoDatCRC=NULL, CachedClientGeoIdxSize=NULL, CachedClientGeoDatSize=NULL WHERE ID = 446;
I'm not at all convinced this is the absolute best solution, but preliminary testing seems to indicate it works. The server complained a lot when brought back up, but permitted the client to connect, and generated new CRC values on the next change to the terrain.
That definitely appears functional, but errors in the server log are worrisome, so it would be nice to find an alternate approach that doesn't generate any error messages at all.