-
Notifications
You must be signed in to change notification settings - Fork 379
Assign constant rather than dynamic blockIndices to modded RMBs #2718
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
drcarademono
wants to merge
7
commits into
Interkarma:master
Choose a base branch
from
drcarademono:AssignNextIndexPR
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 5 commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
57578e1
Change AssignNextIndex to AssignNewIndex
drcarademono 16a8a69
Update WorldDataReplacement.cs
drcarademono c72f281
Fix out-of-scope declaration error
drcarademono 27a0ee3
Cache modded DFBlock on deserialization
drcarademono b4cfb00
Introduce WorldDataReplacementException and catch InvalidCastExceptio…
drcarademono 6b98dbd
Update internal Index value for cached DFBlocks, additional fallback
drcarademono 2af7e31
Moved fallback up
drcarademono File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -17,6 +17,15 @@ | |
|
|
||
| namespace DaggerfallWorkshop.Utility.AssetInjection | ||
| { | ||
| /// <summary> | ||
| /// Thrown when WorldDataReplacement can’t load or parse the expected JSON for a block. | ||
| /// </summary> | ||
| public class WorldDataReplacementException : System.Exception | ||
| { | ||
| public WorldDataReplacementException(string message) : base(message) { } | ||
| public WorldDataReplacementException(string message, System.Exception inner) : base(message, inner) { } | ||
| } | ||
|
|
||
| public struct BlockRecordKey | ||
| { | ||
| public int blockIndex; | ||
|
|
@@ -486,7 +495,7 @@ private static bool AssignBlockIndices(ref DFLocation dfLocation) | |
| // RMB blocks | ||
| foreach (string blockName in dfLocation.Exterior.ExteriorData.BlockNames) | ||
| if (blocksFile.GetBlockIndex(blockName) == -1) | ||
| AssignNextIndex(blockName); | ||
| AssignNewIndex(blockName); | ||
|
|
||
| // RDB blocks | ||
| if (dfLocation.Dungeon.Blocks != null) | ||
|
|
@@ -495,7 +504,7 @@ private static bool AssignBlockIndices(ref DFLocation dfLocation) | |
| { | ||
| string blockName = dungeonBlock.BlockName; | ||
| if (blocksFile.GetBlockIndex(blockName) == -1) | ||
| AssignNextIndex(blockName); | ||
| AssignNewIndex(blockName); | ||
| } | ||
| } | ||
| return true; | ||
|
|
@@ -504,6 +513,83 @@ private static bool AssignBlockIndices(ref DFLocation dfLocation) | |
| return false; | ||
| } | ||
|
|
||
| public static void AssignNewIndex(string blockName) | ||
| { | ||
| string fileName = GetDFBlockReplacementFilename(blockName, WorldDataVariants.NoVariant); | ||
|
|
||
| int jsonBlockIndex; | ||
| DFBlock? dfBlock = null; // Make blockData nullable | ||
| TextAsset blockReplacementJsonAsset; | ||
|
|
||
| // Seek from loose files | ||
| if (File.Exists(Path.Combine(worldDataPath, fileName))) | ||
| { | ||
| string blockReplacementJson = File.ReadAllText(Path.Combine(worldDataPath, fileName)); | ||
| try | ||
| { | ||
| dfBlock = (DFBlock)SaveLoadManager.Deserialize(typeof(DFBlock), blockReplacementJson); | ||
| } | ||
| catch (System.InvalidCastException e) | ||
| { | ||
| Debug.LogError($"Invalid JSON format for block '{blockName}': {e.Message}"); | ||
| throw new WorldDataReplacementException( | ||
| $"Block '{blockName}' JSON could not be cast to DFBlock.", e | ||
| ); | ||
| } | ||
| } | ||
| // Seek from mods | ||
| else if (ModManager.Instance != null && ModManager.Instance.TryGetAsset(fileName, false, out blockReplacementJsonAsset)) | ||
| { | ||
| try | ||
| { | ||
| dfBlock = (DFBlock)SaveLoadManager.Deserialize(typeof(DFBlock), blockReplacementJsonAsset.text); | ||
| } | ||
| catch (System.InvalidCastException e) | ||
| { | ||
| Debug.LogError($"Invalid JSON format for block '{blockName}': {e.Message}"); | ||
| throw new WorldDataReplacementException( | ||
| $"Block '{blockName}' JSON could not be cast to DFBlock.", e | ||
| ); | ||
| } | ||
| } | ||
|
|
||
| // Ensure blockData was successfully assigned | ||
| if (!dfBlock.HasValue) | ||
| { | ||
| Debug.LogError($"Failed to load block data for blockName: {blockName}"); | ||
| throw new WorldDataReplacementException( | ||
| $"Block '{blockName}' does not have a valid Index in its JSON file." | ||
| ); | ||
| } | ||
|
|
||
| // Grab the variant key | ||
| string blockKey = blockName + WorldDataVariants.NoVariant; | ||
|
|
||
| // Check for the "Index" field and assign its value | ||
| jsonBlockIndex = dfBlock.Value.Index; | ||
|
|
||
| // If jsonBlockIndex is invalid (less than or equal to nextBlockIndex), use fallback method | ||
| if (jsonBlockIndex <= nextBlockIndex) | ||
| { | ||
| AssignNextIndex(blockName); | ||
|
|
||
| // Cache the full DFBlock | ||
| if (!blocks.ContainsKey(blockKey)) | ||
| blocks[blockKey] = dfBlock.Value; | ||
|
|
||
| return; | ||
| } | ||
|
|
||
| // Add to cache | ||
| newBlockNames[jsonBlockIndex] = blockName; | ||
| newBlockIndices[blockName] = jsonBlockIndex; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably want to add a fallback to |
||
| Debug.LogFormat("Found a new DFBlock: {0}, (assigned index: {1})", blockName, jsonBlockIndex); | ||
|
|
||
| // Cache the full DFBlock | ||
| if (!blocks.ContainsKey(blockKey)) | ||
| blocks[blockKey] = dfBlock.Value; | ||
| } | ||
|
|
||
| private static void AssignNextIndex(string blockName) | ||
| { | ||
| newBlockNames[nextBlockIndex] = blockName; | ||
|
|
||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cached DFBlock for the
AssignNextIndexfallback also needs to have it's internalIndexvalue updated. What I would recommend:Otherwise
AssignBlockData()will potentially pull the wrong data for RMBs assigned an index through theAssignNextIndex()fallback, causing the player to enter the wrong interior, or throwing an exception because thedoor.resourceIndexis outside the bounds of the RMB'sSubRecords.This bug is clearly visible here with Cliffworm's release version of Lively Cities.
For more insight I'll use the mod Village of Fishguard by dotWayton to demonstrate the bug step by step.


Here you can see Fishguard's RMBs are both set to index 308 within their JSON files.
And here we can see Fishguard's RMBs have been assigned new indexes by

AssignNextIndex():Attempting to enter a house in

FISHER03.RMBresults in this:We can see
AssignBlockData()grabbed two RMBs for our location,FISHER02.RMBandFISHER03.RMB(lines 4531 and 4532). And we can immediately see three things are wrong upon it trying to load the record data (on line 4533): it is pulling fromFISHER02.RMBinstead ofFISHER03.RMB, theBlock Indexand theDoor BlockIndexare both wrong (308instead of1296), and theDoor RecordIndexfar exceeds theBlock SubRecord length(which causes the exception on line 4534). This is because the internal index value for the block wasn't updated, so the door is still using the old block index of308, and sinceFISHER02.RMBis the first block that matches the door's block index of308it gets selected.After the change in the diff above was applied:

It's now pulling from the correct block
FISHER03.RMBinstead ofFISHER02.RMB, with the correctBlock IndexandDoor BlockIndexof1297instead of308, and with theDoor RecordIndexcorrectly within the bounds of theBlock SubRecords length.