[Direct Paste] Servux placement options/sub-region overrides are ignored and entity transforms are incorrect #4
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
I found several fidelity issues in the current Servux Direct Paste implementation on
LitematicaFolia 0.6.1+26.2.The most visible problems are:
Litematica's paste replace mode is ignored.
NONEdoes not work.ALLdoes not work.WITH_NON_AIR.Entities can be spawned at incorrect positions.
Entity coordinates are transformed incorrectly when the placement is rotated.
Entity orientation is not rotated with the schematic placement.
Per-sub-region placement overrides appear to be ignored.
Other standard Servux paste parameters are sent by Litematica and supported by upstream Servux, but are currently not represented in
PasteOptionsor applied byPasteOperation, including at least:ReplaceModePasteLayerBehaviorRenderLayerRangepaste.maxBlocksPerChunkTaskappears to be advisory only and is not actually used to yield large per-chunk block operations.Environment
0.6.1+26.226.226.2-2622The schematic blocks themselves generally paste successfully. The issues below concern placement semantics and entity fidelity.
1.
ReplaceModeis ignoredReproduction
Test A:
ALLCreate/load a schematic that contains an air cavity.
Place it over existing solid blocks.
In Litematica set:
Generic -> pasteReplaceBehavior = AllPaste using Servux Direct Paste.
Expected
Schematic air should also be pasted, removing existing destination blocks.
Actual
Existing blocks remain wherever the schematic contains air.
Test B:
NONEPut existing blocks inside the target area.
Set:
Generic -> pasteReplaceBehavior = NoneDirect Paste the schematic.
Expected
Blocks should only be placed where the destination world currently contains air.
Actual
Non-air schematic blocks overwrite existing destination blocks.
Test C:
WITH_NON_AIRThis is the only mode that currently behaves as expected:
Client / Servux protocol side
This does not appear to be a client-side omission.
Litematica serializes the current paste options into the placement NBT, including:
The inline Direct Paste path then sends that same placement NBT with:
For oversized/transmitted schematics, the schematic payload itself is removed and streamed separately, while placement metadata is retained.
Upstream Servux 26.2 explicitly parses the same values in
LitematicsDataProvider:So
ReplaceModeis already part of the existing Litematica <-> Servux paste protocol.LitematicaFolia cause
In:
src/main/java/fr/ekaii/litematica/protocol/handler/DirectPasteHandler.javathe Direct Paste implementation reads things such as:
and then constructs a simplified
PasteOptions.Conceptually, it currently ends up similar to:
ReplaceModeis not represented.PasteOptionsitself currently has no replace-behavior field:Finally, in:
src/main/java/fr/ekaii/litematica/paste/PasteOperation.javaschematic air is unconditionally discarded:
while destination blocks are later overwritten:
There is no destination-air check.
This effectively hard-codes behavior equivalent to
WITH_NON_AIR.Possible fix
Add a local equivalent of Servux/Litematica's replace behavior to
PasteOptions, for example:and:
Parse the standard protocol field:
for both:
LitematicaPasteThen implement the three upstream semantics.
WITH_NON_AIRSkip schematic air:
ALLDo not discard schematic air.
Air should become a normal planned write so that existing destination blocks can be removed.
NONEBefore writing a schematic non-air block:
Ideally the exact behavior should follow upstream Servux/Litematica's
ReplaceBehaviorimplementation rather than introducing different semantics.2. Entity positions are offset incorrectly
This is reproducible with entities such as minecarts.
Blocks land at the correct placement coordinates, while entities may appear offset from the schematic.
Suspected source-level cause
In
PasteOperation.planRegion()the entity coordinates are effectively handled as:However, Litematica stores entity
Posvalues relative to the region origin when saving a schematic.The client-side save logic effectively does:
Therefore the values in the entity
Poslist are already region-local.LitematicaFolia later calculates the region world start using the region position again:
Subtracting
region.originX/Y/Zfrom entityPosa second time therefore applies the region offset incorrectly.For example:
Instead of:
Possible fix
Do not subtract the region position again:
Then transform the region-local entity position using the same effective placement transform as the region blocks.
Once per-sub-region overrides are implemented, entity coordinates should use that same effective sub-region transform as well.
3. Fractional entity coordinates are rotated incorrectly
Current logic appears to rotate only the floored integer portion of the entity position and then re-add the original fractional components.
Conceptually:
with logic equivalent to:
This means the integer coordinate is rotated, but the fractional X/Z components remain associated with their original axes.
Example:
The current integer-plus-original-fraction approach cannot produce the correct transformed coordinates.
Possible fix
Use a real double-coordinate transform:
Then:
The chunk key can still be calculated afterwards:
4. Entity yaw/orientation is not transformed
In the 26.2 NMS bridge, the entity is loaded from NBT and moved to the requested location while preserving its original yaw/pitch, conceptually:
If the whole schematic is rotated by 90/180/270 degrees, the blocks are rotated but the entity's own orientation is not adjusted.
This may affect:
Possible fix
Apply the effective placement transform to entity orientation before spawning.
For rotation-only behavior, conceptually:
then:
If global/sub-region mirroring is supported, entity orientation should use the same mirror + rotation transformation semantics as upstream Litematica/Servux instead of merely adding yaw.
5.
SubRegionsplacement overrides appear to be ignoredThis appears to be another important Servux compatibility issue.
The Direct Paste handler already recognizes that
SubRegionscontains per-region placement overrides rather than block data.However, the effective sub-region placement does not appear to be reconstructed before
PasteOperationruns.The implementation primarily loads the raw schematic data from:
and starts the paste operation.
This means a client placement that modifies an individual sub-region may still paste the original raw schematic-region layout.
Potentially affected settings include:
Reproduction suggestion
Use a schematic with two sub-regions.
In the Litematica placement configuration:
Then Direct Paste the schematic.
Expected
The server-side paste should exactly match the placement visible on the client.
Suspected current behavior
The raw
.litematicregion arrangement may be pasted instead of the effectiveSubRegionsplacement state.Possible fix
Instead of treating:
as the complete placement definition, reconstruct an effective placement model from fields such as:
The effective transformation should conceptually be:
Disabled sub-regions should not be planned at all.
Upstream Servux implementations such as:
may provide useful reference semantics.
6. Other standard Servux paste settings are not applied
Litematica sends standard placement state including at least:
and upstream Servux parses these fields.
LitematicaFolia currently has no corresponding representation for them in
PasteOptions.As a result, layer-limited pasting is also likely to differ from upstream Servux.
For example, if the user selects a limited paste/render layer range, Direct Paste may still paste the entire schematic.
Possible fix
Add the relevant Servux placement settings to a protocol-level placement model and filter planned blocks before populating the per-chunk write queues.
It may also be useful to audit the remaining upstream
LitematicaPastefields for parity, including where applicable:7.
maxBlocksPerChunkTaskappears to be unusedThe config currently describes:
PasteOptionsalso exposes:but it appears to be advisory only.
The block application path iterates the entire per-chunk write collection in a single scheduled operation rather than using the configured limit to yield.
For a very large/dense chunk, this means all writes may still execute in one region scheduler task.
Possible fix
Split each per-chunk write list into batches of at most:
and reschedule/yield the remaining work on the same owning region.
Care should be taken to preserve paste phases/order, for example:
Suggested architectural approach
Instead of continuing to add individual special cases to
DirectPasteHandler, it may be cleaner to introduce a protocol-level placement description that mirrors the semantic data already provided by Litematica/Servux.For example:
Then both Direct Paste transports:
could decode into the same effective placement model before invoking
PasteOperation.PasteOperationwould then be responsible only for applying an already-decoded placement.This would also reduce behavior differences between the inline and sliced upload paths.
Upstream references
The expected protocol behavior can be compared against upstream Litematica and Servux.
Litematica
SchematicPlacementserializes placement state such as:The Direct Paste path subsequently transmits this placement metadata to the server.
Servux 26.2
fi.dy.masa.servux.dataproviders.LitematicsDataProviderparses fields including:
and uses them when constructing the server-side paste task.
Because these semantics already exist in the upstream Litematica <-> Servux protocol, matching them in the bridge seems preferable to introducing plugin-specific interpretations.
Expected result
Servux Direct Paste through LitematicaFolia should reproduce the same effective placement that the Litematica client displays and that upstream Fabric + Servux would paste:
NONE / WITH_NON_AIR / ALLreplace semanticsmaxBlocksPerChunkTaskThanks for the work on bringing native
.litematic/ Servux support to Paper/Folia.The core Direct Paste transport itself is working well. These issues appear to be concentrated mainly in translating the full Litematica/Servux placement semantics into the current
PasteOptions/PasteOperationpipeline.Hi @stavapin, thank you for an exceptionally detailed and accurate report. Every point checked out against the code and upstream, and it is now fixed and released in 0.8.0+26.2:
One note on your suggested fix for the fractional-coordinate rotation: a plain negation is off by one block cell, so I used the upstream cell-preserving convention (1.0 - v) instead. The audit also turned up two related things now fixed: block states such as stairs rotate and mirror correctly, and structure_void is never pasted. A /litematica save edge case (an entity straddling a chunk border being captured twice) is fixed too.
Validated with 103 unit tests, a 56-check fidelity suite across rotation / mirror / sub-region / layer / entity scenarios, and a real Litematica client paste. The same fixes also ship in 0.9.0+1.21.11 for 1.21.11 servers. Thanks again for the report.