1+ package me .daoge .imager ;
2+
3+ import lombok .Getter ;
4+ import me .daoge .imager .imagemap .ImageMap ;
5+ import me .daoge .imager .imagemap .SplitMode ;
6+ import me .daoge .imager .imagemapstorage .LocalImageMapStorage ;
7+ import me .daoge .imager .imageprovider .LocalImageProvider ;
8+ import me .daoge .imager .manager .ImageMapManager ;
9+ import me .daoge .imager .manager .SimpleImageMapManager ;
10+ import org .allaymc .api .block .data .BlockFace ;
11+ import org .allaymc .api .block .dto .Block ;
12+ import org .allaymc .api .block .dto .PlayerInteractInfo ;
13+ import org .allaymc .api .block .type .BlockTypes ;
14+ import org .allaymc .api .entity .interfaces .EntityPlayer ;
15+ import org .allaymc .api .eventbus .EventHandler ;
16+ import org .allaymc .api .eventbus .event .block .BlockBreakEvent ;
17+ import org .allaymc .api .eventbus .event .block .BlockNeighborUpdateEvent ;
18+ import org .allaymc .api .eventbus .event .block .ItemFrameUseEvent ;
19+ import org .allaymc .api .eventbus .event .player .PlayerInteractBlockEvent ;
20+ import org .allaymc .api .eventbus .event .server .PlayerQuitEvent ;
21+ import org .allaymc .api .form .Forms ;
22+ import org .allaymc .api .form .element .ImageData ;
23+ import org .allaymc .api .item .type .ItemType ;
24+ import org .allaymc .api .item .type .ItemTypes ;
25+ import org .allaymc .api .math .position .Position3i ;
26+ import org .allaymc .api .math .position .Position3ic ;
27+ import org .allaymc .api .pdc .PersistentDataType ;
28+ import org .allaymc .api .plugin .Plugin ;
29+ import org .allaymc .api .registry .Registries ;
30+ import org .allaymc .api .server .Server ;
31+ import org .allaymc .api .utils .identifier .Identifier ;
32+ import org .apache .commons .io .FileUtils ;
33+
34+ import java .io .IOException ;
35+ import java .net .URL ;
36+ import java .util .Arrays ;
37+ import java .util .HashMap ;
38+ import java .util .List ;
39+ import java .util .Map ;
40+
41+ public class Imager extends Plugin {
42+
43+ public static final Identifier KEY_IMAGE_NAME = new Identifier ("imager:image_name" );
44+ public static final ItemType <?> IMAGE_ITEM = ItemTypes .PAINTING ;
45+ protected static final int INTERACT_COOL_DOWN = 5 ;
46+
47+ @ Getter
48+ protected static Imager instance ;
49+ protected Map <EntityPlayer , Long > interactCoolDown = new HashMap <>();
50+ protected Map <EntityPlayer , Position3ic > pos1 = new HashMap <>();
51+ protected Map <EntityPlayer , BlockFace > pos1BlockFace = new HashMap <>();
52+ @ Getter
53+ protected ImageMapManager imageMapManager ;
54+
55+ {
56+ instance = this ;
57+ }
58+
59+ @ Override
60+ public void onEnable () {
61+ var dataPath = this .pluginContainer .dataFolder ();
62+ var provider = new LocalImageProvider (dataPath .resolve ("images" ));
63+ provider .reload ();
64+ var storage = new LocalImageMapStorage (dataPath .resolve ("data.json" ));
65+ this .imageMapManager = new SimpleImageMapManager (storage , provider );
66+ Server .getInstance ().getEventBus ().registerListener (this );
67+ Registries .COMMANDS .register (new ImagerCommand ());
68+ }
69+
70+ @ EventHandler
71+ protected void onPlayerInteractBlock (PlayerInteractBlockEvent event ) {
72+ var currentTick = Server .getInstance ().getTick ();
73+ var player = event .getPlayer ();
74+ PlayerInteractInfo interactInfo = event .getInteractInfo ();
75+ var clickedBlock = interactInfo .getClickedBlock ();
76+
77+ if (isImageMapBlock (clickedBlock )) {
78+ event .setCancelled (true );
79+ if (interactCoolDown .get (player ) != null && currentTick - interactCoolDown .get (player ) <= INTERACT_COOL_DOWN ) {
80+ return ;
81+ }
82+
83+ interactCoolDown .put (player , currentTick );
84+ if (!player .isActualPlayer () || !player .hasPermission ("imager.query_image_info" ).asBoolean ()) {
85+ return ;
86+ }
87+
88+ var imageMap = imageMapManager .getImageMapInPosition (clickedBlock .getPosition ());
89+ var pos1 = imageMap .getPos1 ();
90+ var pos2 = imageMap .getPos2 ();
91+ String info = "§fImageName: §a" + imageMap .getImageName () + "\n " +
92+ "§fImageId: §a" + imageMap .getId () + "\n " +
93+ "§fSplitMode: §a" + imageMap .getMode () + "\n " +
94+ "§fWorldName: §a" + imageMap .getWorldName () + "\n " +
95+ "§fDimId: §a" + imageMap .getDimensionId () + "\n " +
96+ "§fPos1: §a" + pos1 .x () + " " + pos1 .y () + " " + pos1 .z () + "\n " +
97+ "§fPos2: §a" + pos2 .x () + " " + pos2 .y () + " " + pos2 .z ();
98+
99+ Forms .simple ()
100+ .title ("Imager" )
101+ .content (info )
102+ .button ("Remove This Image" , ImageData .ImageType .PATH , "textures/ui/crossout.png" )
103+ .onClick (button -> {
104+ if (imageMapManager .removeImageMap (imageMap .getId ())) {
105+ player .sendMessage ("[Imager] §aImage removed" );
106+ }
107+ })
108+ .sendTo (player .getController ());
109+
110+ return ;
111+ }
112+
113+ var item = player .getItemInHand ();
114+ if (!player .isActualPlayer () || item .getItemType () != IMAGE_ITEM || !item .getPersistentDataContainer ().has (KEY_IMAGE_NAME )) {
115+ return ;
116+ }
117+
118+ event .setCancelled (true );
119+ if (interactCoolDown .get (player ) != null && currentTick - interactCoolDown .get (player ) <= INTERACT_COOL_DOWN ) {
120+ return ;
121+ }
122+
123+ interactCoolDown .put (player , currentTick );
124+ var interactPos = new Position3i (interactInfo .blockFace ().offsetPos (interactInfo .clickedBlockPos ()), player .getDimension ());
125+ if (!pos1 .containsKey (player )) {
126+ //第一个点
127+ pos1 .put (player , interactPos );
128+ pos1BlockFace .put (player , interactInfo .blockFace ());
129+ player .sendMessage ("[Imager] §aPos1 set at: §f(" + interactPos .x + ", " + interactPos .y + ", " + interactPos .z + ")§a, please set pos2" );
130+ } else {
131+ //开始生成图片
132+ var clickedPos1 = pos1 .remove (player );
133+ var clickedPos1BlockFace = pos1BlockFace .remove (player );
134+ //检查是否在一个世界
135+ if (!clickedPos1 .dimension ().getWorld ().getName ().equals (interactPos .dimension ().getWorld ().getName ()) ||
136+ clickedPos1 .dimension ().getDimensionInfo ().dimensionId () != interactPos .dimension ().getDimensionInfo ().dimensionId ()) {
137+ player .sendMessage ("[Imager] §cTwo pos must be in the same level" );
138+ return ;
139+ }
140+ //检查是否为有效的两个点
141+ if (clickedPos1BlockFace != event .getInteractInfo ().blockFace ()) {
142+ player .sendMessage ("[Imager] §Illegal positions, the two positions must have the same block face" );
143+ return ;
144+ }
145+ player .sendMessage ("[Imager] §aPos2 set at: §f(" + interactPos .x + ", " + interactPos .y + ", " + interactPos .z + ")§a, spawning..." );
146+
147+ //模式细节介绍
148+ var info = new StringBuilder ();
149+ for (var mode : SplitMode .values ()) {
150+ var details = mode .details ;
151+ info .append ("§a" ).append (mode .name ()).append (" - §f" ).append (details ).append ("\n " );
152+ }
153+
154+ Forms .custom ()
155+ .title ("Imager" )
156+ .input ("Image Identifier: " )
157+ .dropdown ("Image Mode: " , Arrays .stream (SplitMode .values ()).map (Enum ::name ).toList ())
158+ .slider ("Compressibility" , 0 , 100 , 1 , 100 )
159+ .label (info .toString ())
160+ .onResponse (list -> {
161+ var id = list .get (0 );
162+ if (imageMapManager .containImageMap (id )) {
163+ player .sendMessage ("[Imager] §cDuplicate image id" );
164+ return ;
165+ }
166+
167+ var mode = SplitMode .values ()[Integer .parseInt (list .get (1 ))];
168+ var compressibility = Double .parseDouble (list .get (2 ));
169+ //开始生成图片信息
170+ var imageMap = ImageMap
171+ .builder ()
172+ .pos1 (clickedPos1 )
173+ .pos2 (interactPos )
174+ .worldName (clickedPos1 .dimension ().getWorld ().getName ())
175+ .dimensionId (clickedPos1 .dimension ().getDimensionInfo ().dimensionId ())
176+ .imageName (item .getPersistentDataContainer ().get (KEY_IMAGE_NAME , PersistentDataType .STRING ))
177+ .id (id )
178+ .mode (mode )
179+ .compressibility (compressibility )
180+ .build ();
181+
182+ //通知管理器生成图片
183+ if (imageMapManager .createImageMap (imageMap , event .getInteractInfo ().blockFace (), player .getHorizontalFace ())) {
184+ player .sendMessage ("[Imager] §aSucceed!" );
185+ } else {
186+ player .sendMessage ("[Imager] §cFailed!" );
187+ }
188+ })
189+ .sendTo (player .getController ());
190+ }
191+ }
192+
193+ public void giveImageMapItem (EntityPlayer player , String imageName ) {
194+ var item = IMAGE_ITEM .createItemStack ();
195+ item .setCustomName (imageName );
196+ item .setLore (List .of ("ImageName: " + imageName ));
197+ item .getPersistentDataContainer ().set (KEY_IMAGE_NAME , PersistentDataType .STRING , imageName );
198+ player .tryAddItem (item );
199+ }
200+
201+ /**
202+ * 注意此方法非异步,会阻塞线程
203+ */
204+ public void downloadImage (URL url , String saveName ) throws IOException {
205+ FileUtils .copyURLToFile (url , this .pluginContainer .dataFolder ().resolve ("images" ).resolve (saveName ).toFile ());
206+ }
207+
208+ @ EventHandler
209+ protected void onPlayerQuit (PlayerQuitEvent event ) {
210+ var player = event .getPlayer ().getControlledEntity ();
211+ //清除缓存信息
212+ interactCoolDown .remove (player );
213+ pos1 .remove (player );
214+ pos1BlockFace .remove (player );
215+ }
216+
217+ @ EventHandler
218+ protected void onBlockUpdate (BlockNeighborUpdateEvent event ) {
219+ event .setCancelled (isImageMapBlock (event .getBlock ()));
220+ }
221+
222+ @ EventHandler
223+ protected void onBlockBreak (BlockBreakEvent event ) {
224+ event .setCancelled (isImageMapBlock (event .getBlock ()));
225+ }
226+
227+ @ EventHandler
228+ protected void onItemFrameUse (ItemFrameUseEvent event ) {
229+ event .setCancelled (isImageMapBlock (event .getBlock ()));
230+ }
231+
232+ protected boolean isImageMapBlock (Block block ) {
233+ return block .getBlockType () == BlockTypes .FRAME && imageMapManager .containImageMapInPosition (block .getPosition ());
234+ }
235+ }
0 commit comments