-
Notifications
You must be signed in to change notification settings - Fork 417
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Completes the data attachment API with client-server syncing capabilities. ## Motivation The existing API works great for attaching data to game objects, be they serverside or clientside, but lacks any ability to synchronize between the two. A mod that wants to add a "thirst" mechanic can easily do so on the server side by attaching an integer to every player. However, the mod may also want to use this information to render additional HUD elements on the client. Currently, informing the client of this data can only be done manually, which is cumbersome, error-prone, and is much better-suited as an API feature. ## API Changes The API doesn't change a lot (at least compared to the implementation), with a few new methods and one new class. One new method has been added to `AttachmentRegistry.Builder`, namely `syncWith`. It declares that an attachment type may be synchronized with some clients, and takes a `PacketCodec` to encode attachment data over the network, as well as an element of the new `AttachmentSyncPredicate` interface. This interface extends `BiPredicate<AttachmentTarget, ServerPlayerEntity>` to allow for user-defined predicates, and provides some common presets: * `all()`: attachment data will be synchronized with all clients (that track the target). * `targetOnly()`: attachment data will only be synchronized with the target it is attached to, when it is a player. If the target is not a player, it won't be synchronized with any client. * `allButTarget()`: reverse of the above. For non-player targets, attachment data will be synchronized with all clients. **NOTE**: for a user-defined condition, whether attachment data is synchronized with a client can change at runtime (e.g. "sync only with operators" when a player changes operator status). A specialized method to "refresh" data was considered, but in the end discarded due to complexity. It falls to individual mods to handle these edge cases. AttachmentType also gets one new `isSynced` method to know whether a given attachment type can be synced. ## Usage Here is how one could register an attachment for a "thirst" meter like mentioned above. ```java public static final AttachmentType<Integer> THIRST = AttachmentRegistry.<Integer>builder() .initializer(() -> 20) // start with a default value like hunger .persistent(Codec.INT) // persist across restarts .syncWith(PacketCodecs.VAR_INT.cast(), AttachmentSyncPredicate.targetOnly()) // only the player's own client needs the value for rendering .buildAndRegister(Identifier.of("modid", "thirst")); ```
- Loading branch information
Showing
39 changed files
with
1,798 additions
and
62 deletions.
There are no files selected for viewing
This file contains 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
41 changes: 41 additions & 0 deletions
41
...i-v1/src/client/java/net/fabricmc/fabric/impl/attachment/client/AttachmentSyncClient.java
This file contains 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 |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/* | ||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package net.fabricmc.fabric.impl.attachment.client; | ||
|
||
import net.fabricmc.api.ClientModInitializer; | ||
import net.fabricmc.fabric.api.client.networking.v1.ClientConfigurationNetworking; | ||
import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; | ||
import net.fabricmc.fabric.impl.attachment.sync.AttachmentSync; | ||
import net.fabricmc.fabric.impl.attachment.sync.s2c.AttachmentSyncPayloadS2C; | ||
import net.fabricmc.fabric.impl.attachment.sync.s2c.RequestAcceptedAttachmentsPayloadS2C; | ||
|
||
public class AttachmentSyncClient implements ClientModInitializer { | ||
@Override | ||
public void onInitializeClient() { | ||
// config | ||
ClientConfigurationNetworking.registerGlobalReceiver( | ||
RequestAcceptedAttachmentsPayloadS2C.ID, | ||
(payload, context) -> context.responseSender().sendPacket(AttachmentSync.createResponsePayload()) | ||
); | ||
|
||
// play | ||
ClientPlayNetworking.registerGlobalReceiver( | ||
AttachmentSyncPayloadS2C.ID, | ||
(payload, context) -> payload.attachments().forEach(attachmentChange -> attachmentChange.apply(context.client().world)) | ||
); | ||
} | ||
} |
This file contains 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
This file contains 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
56 changes: 56 additions & 0 deletions
56
...t-api-v1/src/main/java/net/fabricmc/fabric/api/attachment/v1/AttachmentSyncPredicate.java
This file contains 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 |
---|---|---|
@@ -0,0 +1,56 @@ | ||
/* | ||
* Copyright (c) 2016, 2017, 2018, 2019 FabricMC | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
|
||
package net.fabricmc.fabric.api.attachment.v1; | ||
|
||
import java.util.function.BiPredicate; | ||
|
||
import org.jetbrains.annotations.ApiStatus; | ||
|
||
import net.minecraft.server.network.ServerPlayerEntity; | ||
|
||
/** | ||
* A predicate that determines, for a specific attachment type, whether the data should be synchronized with a | ||
* player's client, given the player's {@link ServerPlayerEntity} and the {@linkplain AttachmentTarget} the data is linked to. | ||
* | ||
* <p>The class extends {@link BiPredicate} to allow for custom predicates, outside the ones provided by methods.</p> | ||
*/ | ||
@ApiStatus.NonExtendable | ||
@FunctionalInterface | ||
public interface AttachmentSyncPredicate extends BiPredicate<AttachmentTarget, ServerPlayerEntity> { | ||
/** | ||
* @return a predicate that syncs an attachment with all clients | ||
*/ | ||
static AttachmentSyncPredicate all() { | ||
return (t, p) -> true; | ||
} | ||
|
||
/** | ||
* @return a predicate that syncs an attachment only with the target it is attached to, when that is a player. If the | ||
* target isn't a player, the attachment will be synced with no clients. | ||
*/ | ||
static AttachmentSyncPredicate targetOnly() { | ||
return (target, player) -> target == player; | ||
} | ||
|
||
/** | ||
* @return a predicate that syncs an attachment with every client except the target it is attached to, when that is a player. | ||
* When the target isn't a player, the attachment will be synced with all clients. | ||
*/ | ||
static AttachmentSyncPredicate allButTarget() { | ||
return (target, player) -> target != player; | ||
} | ||
} |
This file contains 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
This file contains 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
This file contains 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
Oops, something went wrong.