1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
|
package org.challman.pantheon_parser;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class EntityMap extends JPanel {
private Map<String, Entity> entities = new ConcurrentHashMap<>();
private Entity player;
private long entityTimeout = 10000;
private volatile boolean needsRepaint = false;
private double scale = 1.0;
private JButton zoomInButton, zoomOutButton;
private JButton closeButton;
private int controlPanelHeight = 25;
// Drag variables
private Point dragStartPoint;
private Point windowStartPoint;
public EntityMap() {
setOpaque(true);
setBackground(new Color(30, 30, 30));
setPreferredSize(new Dimension(300, 300));
setLayout(new BorderLayout());
// Create control panel
JPanel controlPanel = createControlPanel();
add(controlPanel, BorderLayout.NORTH);
// Add mouse listeners for dragging
addMouseListeners();
Timer timer = new Timer(33, e -> {
if (needsRepaint) {
repaint();
needsRepaint = false;
}
});
timer.start();
}
public Entity getEntity(String id) {
return entities.get(id);
}
private JPanel createControlPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setOpaque(false);
panel.setPreferredSize(new Dimension(300, controlPanelHeight));
panel.setBorder(BorderFactory.createEmptyBorder(2, 5, 2, 5));
// Left side: drag handle
JLabel dragHandle = new JLabel("≡ Minimap");
dragHandle.setForeground(Color.LIGHT_GRAY);
dragHandle.setFont(new Font("Arial", Font.PLAIN, 10));
dragHandle.setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
// Right side: control buttons
JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 3, 0));
buttonPanel.setOpaque(false);
zoomOutButton = new JButton("-");
zoomInButton = new JButton("+");
closeButton = new JButton("×");
styleButton(zoomOutButton);
styleButton(zoomInButton);
styleCloseButton(closeButton);
zoomOutButton.addActionListener(e -> zoomOut());
zoomInButton.addActionListener(e -> zoomIn());
closeButton.addActionListener(e -> System.exit(0));
buttonPanel.add(zoomOutButton);
buttonPanel.add(zoomInButton);
buttonPanel.add(closeButton);
panel.add(dragHandle, BorderLayout.WEST);
panel.add(buttonPanel, BorderLayout.EAST);
return panel;
}
private void styleButton(JButton button) {
button.setPreferredSize(new Dimension(25, 18));
button.setFont(new Font("Arial", Font.BOLD, 10));
button.setFocusable(false);
button.setBackground(new Color(60, 60, 60));
button.setForeground(Color.WHITE);
button.setBorder(BorderFactory.createLineBorder(Color.GRAY));
button.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
button.setBackground(new Color(80, 80, 80));
}
@Override
public void mouseExited(MouseEvent e) {
button.setBackground(new Color(60, 60, 60));
}
});
}
private void styleCloseButton(JButton button) {
button.setPreferredSize(new Dimension(25, 18));
button.setFont(new Font("Arial", Font.BOLD, 12));
button.setFocusable(false);
button.setBackground(new Color(100, 60, 60));
button.setForeground(Color.WHITE);
button.setBorder(BorderFactory.createLineBorder(new Color(120, 80, 80)));
button.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
button.setBackground(new Color(140, 80, 80));
}
@Override
public void mouseExited(MouseEvent e) {
button.setBackground(new Color(100, 60, 60));
}
});
}
private void addMouseListeners() {
MouseAdapter dragAdapter = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
dragStartPoint = e.getPoint();
Window window = SwingUtilities.getWindowAncestor(EntityMap.this);
if (window != null) {
windowStartPoint = window.getLocation();
}
}
@Override
public void mouseDragged(MouseEvent e) {
if (dragStartPoint != null && windowStartPoint != null) {
Point currentPoint = e.getPoint();
int deltaX = currentPoint.x - dragStartPoint.x;
int deltaY = currentPoint.y - dragStartPoint.y;
Window window = SwingUtilities.getWindowAncestor(EntityMap.this);
if (window != null) {
Point newLocation = new Point(
windowStartPoint.x + deltaX,
windowStartPoint.y + deltaY
);
window.setLocation(newLocation);
}
}
}
@Override
public void mouseReleased(MouseEvent e) {
dragStartPoint = null;
windowStartPoint = null;
}
};
// Add listeners to the entire panel for dragging
addMouseListener(dragAdapter);
addMouseMotionListener(dragAdapter);
// Also add to control panel for easier dragging
Component[] components = getComponents();
for (Component comp : components) {
if (comp instanceof JPanel) {
comp.addMouseListener(dragAdapter);
comp.addMouseMotionListener(dragAdapter);
}
}
}
private void zoomIn() {
scale *= 1.2;
if (scale > 10.0) scale = 10.0;
needsRepaint = true;
}
private void zoomOut() {
scale /= 1.2;
if (scale < 0.1) scale = 0.1;
needsRepaint = true;
}
public void updateEntity(Entity entity, Entity currentPlayer) {
entities.put(entity.id, entity);
if (currentPlayer != null) {
this.player = currentPlayer;
}
cleanupOldEntities();
needsRepaint = true;
}
public Collection<Entity> getAllEntities() {
return entities.values();
}
private void cleanupOldEntities() {
long currentTime = System.currentTimeMillis();
entities.entrySet().removeIf(entry -> {
Entity entity = entry.getValue();
return entity != player && entity.lastUpdated != -1 && (currentTime - entity.lastUpdated) > entityTimeout;
});
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
if (player == null) {
g2d.dispose();
return;
}
// Calculate available space for the circle
int width = getWidth();
int height = getHeight() - controlPanelHeight;
int size = Math.min(width, height);
int mapRadius = size / 2;
int centerX = width / 2;
int centerY = controlPanelHeight + (height / 2);
// Draw circular map background (maximized)
g2d.setColor(new Color(20, 20, 20));
g2d.fillOval(centerX - mapRadius, centerY - mapRadius, size, size);
// Draw map border
g2d.setColor(new Color(100, 100, 100));
g2d.setStroke(new BasicStroke(2));
g2d.drawOval(centerX - mapRadius, centerY - mapRadius, size, size);
// Draw grid lines
g2d.setColor(new Color(50, 50, 50));
g2d.setStroke(new BasicStroke(1));
g2d.drawLine(centerX, centerY - mapRadius, centerX, centerY + mapRadius);
g2d.drawLine(centerX - mapRadius, centerY, centerX + mapRadius, centerY);
// Calculate scale with zoom factor
double maxDistance = 50.0 / scale;
double distanceScale = mapRadius / maxDistance;
// Draw other entities
g2d.setFont(new Font("Arial", Font.PLAIN, 9));
for (Entity entity : entities.values()) {
if (entity.id.equals(player.id)) continue;
double dx = entity.x - player.x;
double dz = entity.z - player.z;
double distance = Math.sqrt(dx * dx + dz * dz);
if (distance <= maxDistance) {
int x = centerX + (int)(dx * distanceScale);
int y = centerY - (int)(dz * distanceScale);
double distFromCenter = Math.sqrt((x - centerX) * (x - centerX) + (y - centerY) * (y - centerY));
if (distFromCenter <= mapRadius - 5) {
if (entity.type == 2) {
g2d.setColor(Color.CYAN);
} else if (entity.type == 3) {
g2d.setColor(Color.ORANGE);
} else {
g2d.setColor(Color.WHITE);
}
g2d.fillOval(x - 3, y - 3, 6, 6);
if (distance < maxDistance * 0.9) {
g2d.setColor(Color.WHITE);
g2d.drawString(entity.id, x + 5, y);
}
}
}
}
// Draw player
g2d.setColor(Color.RED);
g2d.fillOval(centerX - 4, centerY - 4, 8, 8);
// Draw direction indicator
double directionAngle = Math.toRadians(player.heading);
int dirX = centerX + (int)((mapRadius - 10) * Math.sin(directionAngle));
int dirY = centerY - (int)((mapRadius - 10) * Math.cos(directionAngle));
g2d.setColor(Color.YELLOW);
g2d.setStroke(new BasicStroke(2));
g2d.drawLine(centerX, centerY, dirX, dirY);
// Draw UI elements in corners
drawCornerElements(g2d, centerX, centerY, mapRadius);
g2d.dispose();
}
private void drawCornerElements(Graphics2D g2d, int centerX, int centerY, int mapRadius) {
g2d.setColor(Color.WHITE);
g2d.setFont(new Font("Arial", Font.PLAIN, 10));
// Top-left: Scale indicator
int topLeftX = centerX - mapRadius + 5;
int topLeftY = centerY - mapRadius + 15;
g2d.drawString(String.format("Zoom: %.1fx", scale), topLeftX, topLeftY);
// Top-right: Entity count
int topRightX = centerX + mapRadius - 60;
int topRightY = centerY - mapRadius + 15;
int entityCount = entities.size() - (player != null ? 1 : 0);
g2d.drawString(String.format("Entities: %d", entityCount), topRightX, topRightY);
// Bottom-left: Player coordinates
int bottomLeftX = centerX - mapRadius + 5;
int bottomLeftY = centerY + mapRadius - 5;
g2d.drawString(String.format("(%.1f, %.1f)", player.x, player.z), bottomLeftX - 10, bottomLeftY);
// Bottom-right: Compass heading
int bottomRightX = centerX + mapRadius - 50;
int bottomRightY = centerY + mapRadius - 5;
g2d.drawString(String.format("%.0f°", player.heading), bottomRightX, bottomRightY);
// Draw mini compass in top-right corner
drawMiniCompass(g2d, centerX + mapRadius - 20, centerY - mapRadius + 35, player.heading);
}
private void drawMiniCompass(Graphics2D g2d, int x, int y, float heading) {
int radius = 8;
g2d.setColor(new Color(50, 50, 50, 200));
g2d.fillOval(x - radius, y - radius, radius * 2, radius * 2);
g2d.setColor(Color.WHITE);
g2d.drawOval(x - radius, y - radius, radius * 2, radius * 2);
// Draw N indicator
g2d.setFont(new Font("Arial", Font.BOLD, 8));
g2d.drawString("N", x - 2, y - radius - 1);
double needleAngle = Math.toRadians(heading);
int needleX = x + (int)(radius * Math.sin(needleAngle));
int needleY = y - (int)(radius * Math.cos(needleAngle));
g2d.setColor(Color.RED);
g2d.setStroke(new BasicStroke(1.5f));
g2d.drawLine(x, y, needleX, needleY);
g2d.setStroke(new BasicStroke(1));
}
}
|