Denis Kosher Posted May 29, 2021 Report Share Posted May 29, 2021 (edited) Hi guys, I'm trying to implement following logic: User puts item into active slot. Right clicks on specific block Pop-up asking for text entry is shown When pop-up content is saved (and only if) - save entered text into item, and block coordinates I've implemented it in the following way: if (!(byEntity.World is IClientWorldAccessor)) { return; } string prevName = _name == null ? "" : _name; BlockPos prevPos = _pos; GuiDialogBlockEntityTextInput dlg = new GuiDialogBlockEntityTextInput("Enter your text", bec.Pos, prevName, bec.Api as ICoreClientAPI, 500); dlg.OnTextChanged = (text) => { _pos = bec.Pos; _name = text; }; dlg.OnCloseCancel = () => { _name = prevName == "" ? null : _name; _pos = _prevPos; }; dlg.TryOpen(); But, this _name property is set only on Client's side, I've tried to use : slot.Itemstack.Attributes.SetString("name", _name); But they are also set only on client's side. So the question is - how can I send information from client's copy of an item to server's copy of an item? Edited May 29, 2021 by Denis Kosher Link to comment Share on other sites More sharing options...
Denis Kosher Posted June 7, 2021 Author Report Share Posted June 7, 2021 Found solution for this problem - right now the only way to synchronize something between client and server (in this specific order) - is to use BlockEntity (there is ItemEntity class with same functionality, but I was not able to find a way how to use it): 1. You'll need to create block entity which will be used as mediator for data synchronization, and add field which will store item for synchronization (either as ItemSlot, either as HashMap of itemId and itemSlot): public class BEMyEntity : BlockEntity { private ItemSlot _itemForSynch; 2. Before UI is opened - populate this field from item, in the BlockEntity (I did it as part of OnHeldInteractStep method, when user clicks on Mediator object): public override bool OnHeldInteractStep(float secondsUsed, ItemSlot slot, EntityAgent byEntity, BlockSelection blockSel, EntitySelection entitySel) { if (byEntity.World is IClientWorldAccessor) { ... Other logic } else { BEMyEntity bec = byEntity.World.BlockAccessor.GetBlockEntity(blockSel.Position) as BEMyEntity; if (bec != null) { bec.setItemForSynch(slot); } } 3. When text is changed - send packet to the server side copy of BlockEntity if (byEntity.World is IClientWorldAccessor) { GuiDialogBlockEntityTextInput dlg = new GuiDialogBlockEntityTextInput(Lang.Get("message"), bec.Pos, "", bec.Api as ICoreClientAPI, 500); dlg.OnTextChanged = (text) => { int packetId = (int)EnumSignPacketId.SaveText; using (MemoryStream ms = new MemoryStream()) { BinaryWriter writer = new BinaryWriter(ms); writer.Write(text); byte[] data = ms.ToArray(); (bec.Api as ICoreClientAPI).Network.SendBlockEntityPacket(bec.Pos.X, bec.Pos.Y, bec.Pos.Z, packetId, data); } }; dlg.OnCloseCancel = () => { int packetId = (int)EnumSignPacketId.SaveText; (bec.Api as ICoreClientAPI).Network.SendBlockEntityPacket(bec.Pos.X, bec.Pos.Y, bec.Pos.Z, packetId, null); }; dlg.TryOpen(); } 4. Add handler into blockEntity that will synchronize client and server side copy of items on package receive: public override void OnReceivedClientPacket(IPlayer player, int packetid, byte[] data) { string text = ""; if (packetid == (int)EnumSignPacketId.SaveText) { if (data != null) { using (MemoryStream ms = new MemoryStream(data)) { BinaryReader reader = new BinaryReader(ms); text = reader.ReadString(); if (text == null) text = ""; } if (text == null) text = ""; } if (_itemToSynch != null) { _itemToSynch.Itemstack.Attributes.SetString("name", text); } } if (packetid == (int)EnumSignPacketId.CancelEdit) { } } Link to comment Share on other sites More sharing options...
Recommended Posts