diff --git a/src/datagen/generated/minecolonies/data/minecolonies/compatibility/itemnbtmatching.json b/src/datagen/generated/minecolonies/data/minecolonies/compatibility/itemnbtmatching.json index 9f489aa0e1e..97ed90c1a2a 100644 --- a/src/datagen/generated/minecolonies/data/minecolonies/compatibility/itemnbtmatching.json +++ b/src/datagen/generated/minecolonies/data/minecolonies/compatibility/itemnbtmatching.json @@ -2608,6 +2608,14 @@ { "item": "minecraft:fern" }, + { + "checkednbtkeys": [ + "minecraft:map_color", + "minecraft:map_decorations", + "minecraft:map_id" + ], + "item": "minecraft:filled_map" + }, { "item": "minecraft:fire_charge" }, diff --git a/src/main/java/com/minecolonies/api/colony/buildings/workerbuildings/ITownHallView.java b/src/main/java/com/minecolonies/api/colony/buildings/workerbuildings/ITownHallView.java index 27a05f08579..c98236dc62b 100755 --- a/src/main/java/com/minecolonies/api/colony/buildings/workerbuildings/ITownHallView.java +++ b/src/main/java/com/minecolonies/api/colony/buildings/workerbuildings/ITownHallView.java @@ -3,6 +3,11 @@ import com.minecolonies.api.colony.buildings.views.IBuildingView; import com.minecolonies.api.colony.colonyEvents.descriptions.IColonyEventDescription; import com.minecolonies.api.colony.permissions.PermissionEvent; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.RegistryFriendlyByteBuf; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.world.level.saveddata.maps.MapId; +import net.minecraft.world.level.saveddata.maps.MapItemSavedData; import java.util.List; @@ -28,4 +33,20 @@ public interface ITownHallView extends IBuildingView * @return true if so. */ boolean canPlayerUseTP(); + + /** + * Getter for the mapdata. + * @return the original list. + */ + List getMapDataList(); + + public record MapEntry(MapId mapId, MapItemSavedData mapData) + { + public static final StreamCodec STREAM_CODEC = + StreamCodec.composite(MapId.STREAM_CODEC, + MapEntry::mapId, + StreamCodec.of((buf, data) -> buf.writeNbt(data.save(new CompoundTag(), buf.registryAccess())), buf -> MapItemSavedData.load(buf.readNbt(), buf.registryAccess())), + MapEntry::mapData, + MapEntry::new); + } } diff --git a/src/main/java/com/minecolonies/core/client/gui/map/MinecraftMap.java b/src/main/java/com/minecolonies/core/client/gui/map/MinecraftMap.java index 7d69d3b58f9..66136ba709d 100644 --- a/src/main/java/com/minecolonies/core/client/gui/map/MinecraftMap.java +++ b/src/main/java/com/minecolonies/core/client/gui/map/MinecraftMap.java @@ -3,18 +3,20 @@ import com.ldtteam.blockui.BOGuiGraphics; import com.ldtteam.blockui.Pane; import com.ldtteam.blockui.PaneParams; -import net.minecraft.client.renderer.texture.DynamicTexture; -import net.minecraft.resources.ResourceLocation; -import net.minecraft.world.level.material.MapColor; +import net.minecraft.client.Minecraft; +import net.minecraft.world.level.saveddata.maps.MapId; import net.minecraft.world.level.saveddata.maps.MapItemSavedData; /** * Simple minecraft map element. */ -public class MinecraftMap extends Pane implements AutoCloseable +public class MinecraftMap extends Pane { - private DynamicTexture texture; - private ResourceLocation textureResLoc; + public static final int MAP_SIZE = 128; + public static final int MAP_CENTER = 64; + + private MapItemSavedData mapData; + private MapId mapId; /** * Default Constructor. @@ -38,25 +40,10 @@ public MinecraftMap(final PaneParams params) * Set the fitting map data. * @param mapData the mapData to set. */ - public void setMapData(final MapItemSavedData mapData) + public void setMapData(final MapId mapId, final MapItemSavedData mapData) { - if (texture != null) - { - freeTexture(); - } - - texture = new DynamicTexture(128, 128, false); - - for (int y = 0; y < 128; ++y) - { - for (int x = 0; x < 128; ++x) - { - texture.getPixels().setPixelRGBA(x, y, MapColor.getColorFromPackedId(mapData.colors[x + y * 128])); - } - } - - texture.upload(); - textureResLoc = mc.getTextureManager().register("minecolonies_map/" + id, texture); + this.mapId = mapId; + this.mapData = mapData; } /** @@ -68,27 +55,17 @@ public void setMapData(final MapItemSavedData mapData) @Override public void drawSelf(final BOGuiGraphics ms, final double mx, final double my) { - if (textureResLoc != null) + if (mapData != null) { - blit(ms.pose(), textureResLoc, x, y, width, height); - } - } + ms.pose().pushPose(); + ms.pose().translate(x, y, 0.01f); + ms.pose().scale(getWidth() / MAP_SIZE, getHeight() / MAP_SIZE, 1); - private void freeTexture() - { - if (textureResLoc != null) - { - texture.close(); - mc.getTextureManager().release(textureResLoc); + // if fifth bool == false => enable all map decos + Minecraft.getInstance().gameRenderer.getMapRenderer().render(ms.pose(), ms.bufferSource(), mapId, mapData, true, 15728880); - texture = null; - textureResLoc = null; + ms.flush(); + ms.pose().popPose(); } } - - @Override - public void close() - { - freeTexture(); - } } diff --git a/src/main/java/com/minecolonies/core/client/gui/map/WindowColonyMap.java b/src/main/java/com/minecolonies/core/client/gui/map/WindowColonyMap.java index 28eaccee0a7..7471fc9488d 100644 --- a/src/main/java/com/minecolonies/core/client/gui/map/WindowColonyMap.java +++ b/src/main/java/com/minecolonies/core/client/gui/map/WindowColonyMap.java @@ -9,15 +9,15 @@ import com.ldtteam.blockui.controls.Text; import com.ldtteam.blockui.views.View; import com.ldtteam.blockui.views.ZoomDragView; -import com.ldtteam.common.language.LanguageHandler; import com.minecolonies.api.client.render.modeltype.ISimpleModelType; import com.minecolonies.api.client.render.modeltype.registry.IModelTypeRegistry; import com.minecolonies.api.colony.ICitizenDataView; import com.minecolonies.api.colony.IColonyView; import com.minecolonies.api.colony.buildings.views.IBuildingView; +import com.minecolonies.api.colony.buildings.workerbuildings.ITownHallView; +import com.minecolonies.api.colony.buildings.workerbuildings.ITownHallView.MapEntry; import com.minecolonies.api.util.constant.Constants; import com.minecolonies.core.client.gui.AbstractWindowSkeleton; -import com.minecolonies.core.colony.buildings.workerbuildings.BuildingTownHall; import com.minecolonies.core.entity.citizen.EntityCitizen; import com.minecolonies.core.network.messages.client.colony.ColonyListMessage; import com.minecolonies.core.network.messages.server.colony.OpenInventoryMessage; @@ -37,9 +37,16 @@ import static com.minecolonies.api.research.util.ResearchConstants.COLOR_TEXT_FULFILLED; import static com.minecolonies.api.util.constant.WindowConstants.BUTTON_EXIT; import static com.minecolonies.api.util.constant.WindowConstants.BUTTON_INVENTORY; +import static com.minecolonies.core.client.gui.map.MinecraftMap.MAP_CENTER; public class WindowColonyMap extends AbstractWindowSkeleton { + /** + * Static multiplier to make background map larger -> icons smaller + */ + private static final int MAP_ZOOM = 2; + private static final int MAP_SIZE = MinecraftMap.MAP_SIZE * MAP_ZOOM; + /** * Link to the xml file of the window. */ @@ -71,12 +78,11 @@ public class WindowColonyMap extends AbstractWindowSkeleton private Map citizens = new HashMap<>(); private Map buildings = new HashMap<>(); private Map coloniesImages = new HashMap<>(); - private List maps = new ArrayList<>(); /** * building reference of the view */ - private IBuildingView building; + private ITownHallView building; /** * Scale formatting @@ -91,28 +97,59 @@ public class WindowColonyMap extends AbstractWindowSkeleton /** * Check if it has maps. */ - private boolean hasMaps = false; + private final boolean hasMaps; + + /** + * Top left corner for map positioning + */ + private final BlockPos worldPosRoot; /** * Constructor for the skeleton class of the windows. * * @param building The building the info window is for. */ - public WindowColonyMap(final IBuildingView building) + public WindowColonyMap(final ITownHallView building) { super(Constants.MOD_ID + WINDOW_RESOURCE); this.building = building; - playerPos = new BlockPos(Minecraft.getInstance().player.blockPosition().getX(), 0, Minecraft.getInstance().player.blockPosition().getZ()); - final ZoomDragView parent = findPaneOfTypeByID("dragView", ZoomDragView.class); - dragView = new ZoomDragView(); - dragView.setSize(parent.getWidth(), parent.getHeight()); - dragView.setPosition(parent.getX(), parent.getY()); - parent.addChild(dragView); - if (addMaps()) + playerPos = Minecraft.getInstance().player.blockPosition(); + dragView = findPaneOfTypeByID("dragView", ZoomDragView.class); + + hasMaps = !building.getMapDataList().isEmpty(); + findPaneByID("warning").setVisible(!hasMaps); + + if (hasMaps) { + // compute top left corner using all provided maps + // then shift even more to top left to provide spacing for one more "fake" map + // another fake map is added to bottom right for same reason + int minX = Integer.MAX_VALUE, minZ = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxZ = Integer.MIN_VALUE, maxScale = 0; + for (final MapEntry entry : building.getMapDataList()) + { + final int scale = 1 << entry.mapData().scale; + maxScale = Math.max(maxScale, scale); + minX = Math.min(minX, entry.mapData().centerX - MAP_CENTER * scale); + maxX = Math.max(maxX, entry.mapData().centerX + MAP_CENTER * scale); + minZ = Math.min(minZ, entry.mapData().centerZ - MAP_CENTER * scale); + maxZ = Math.max(maxZ, entry.mapData().centerZ + MAP_CENTER * scale); + } + worldPosRoot = new BlockPos(minX - MAP_SIZE * maxScale, 0, minZ - MAP_SIZE * maxScale); + + addMaps(); + final MinecraftMap bottomRightFake = new MinecraftMap(); + bottomRightFake.setSize(MAP_SIZE * maxScale, MAP_SIZE * maxScale); + bottomRightFake.setID("mapBottomRight" + maxX + "-" + maxZ); + putPaneTopLeftCornerAtWorldPos(bottomRightFake, new BlockPos(maxX, 0, maxZ)); + dragView.addChild(bottomRightFake); + addCitizens(building.getColony()); addCenterPos(); } + else + { + worldPosRoot = null; + } registerButton(BUTTON_EXIT, () -> building.openGui(false)); registerButton(BUTTON_INVENTORY, this::inventoryClicked); @@ -129,39 +166,22 @@ private void inventoryClicked() } /** - * Add the map. Return false if has no maps. - * @return true if so. + * Add the map. */ - private boolean addMaps() + private void addMaps() { - for (final MinecraftMap map : maps) + for (final MapEntry mapEntry : building.getMapDataList()) { - dragView.removeChild(map); - map.close(); - } - - maps.clear(); - - for (final MapItemSavedData mapData : ((BuildingTownHall.View) building).getMapDataList()) - { - if (mapData.scale != 0) - { - continue; - } - - hasMaps = true; + final MapItemSavedData mapData = mapEntry.mapData(); + final int scale = 1 << mapData.scale; final MinecraftMap mapImage = new MinecraftMap(); - mapImage.setPosition(worldPosToUIPos(new BlockPos(mapData.centerX - 64, 0, 0)).getX(), worldPosToUIPos(new BlockPos(0, 0, mapData.centerZ - 64)).getZ()); + putPaneTopLeftCornerAtWorldPos(mapImage, new BlockPos(mapData.centerX - MAP_CENTER * scale, 0, mapData.centerZ - MAP_CENTER * scale)); mapImage.setID("map" + mapData.centerX + "-" + mapData.centerZ); - mapImage.setMapData(mapData); - mapImage.setSize((int) (512*currentScale), (int) (512*currentScale)); - dragView.addChild(mapImage, 0); - maps.add(mapImage); + mapImage.setMapData(mapEntry.mapId(), mapData); + mapImage.setSize(MAP_SIZE * scale, MAP_SIZE * scale); + dragView.addChild(mapImage); } - - findPaneByID("warning").setVisible(!hasMaps); - return hasMaps; } /** @@ -186,7 +206,7 @@ public void onUpdate() final EntityCitizen citizen = (EntityCitizen) building.getColony().getWorld().getEntity(entry.getKey().getEntityId()); if (citizen != null) { - entry.getValue().setPosition(worldPosToUIPos(citizen.blockPosition()).getX(), worldPosToUIPos(citizen.blockPosition()).getZ()); + putPaneCenterAtWorldPos(entry.getValue(), citizen.blockPosition()); } } @@ -208,11 +228,6 @@ private void updateScale() updateColonyInfoImage(info); } - for (final ColonyListMessage.ColonyInfo info : colonies) - { - updateColonyInfoImage(info); - } - for (final IBuildingView buildingView : building.getColony().getBuildings()) { updateBuildingView(buildingView); @@ -252,7 +267,6 @@ private void updateScale() } } - addMaps(); findPaneOfTypeByID("scale", Text.class).setText(Component.literal(scaleformet.format(1 / currentScale) + "x")); } @@ -279,8 +293,7 @@ private void updateColonyInfoImage(final ColonyListMessage.ColonyInfo colonyInfo if (currentScale < COLONY_DETAIL_SCALE) { - colonyPane.setPosition(worldPosToUIPos(colonyInfo.getCenter()).getX() - colonyPane.getWidth() / 2, - worldPosToUIPos(colonyInfo.getCenter()).getZ() - colonyPane.getHeight() / 2); + putPaneCenterAtWorldPos(colonyPane, colonyInfo.getCenter()); colonyPane.on(); } else @@ -297,7 +310,13 @@ private void addCenterPos() final Image citizenImage = new Image(); citizenImage.setImage(new ResourceLocation(Constants.MOD_ID, "textures/gui/red_wax_home.png"), false); citizenImage.setSize(16, 16); - citizenImage.setPosition(worldPosToUIPos(playerPos).getX(), worldPosToUIPos(playerPos).getZ()); + putPaneTopLeftCornerAtWorldPos(citizenImage, playerPos); + + dragView.setScaleRaw(4.0 / 5); + dragView.setScrollX(dragView.calcInverseAbsoluteX(citizenImage.getX()) - dragView.getWidth() / 2); + dragView.setScrollY(dragView.calcInverseAbsoluteY(citizenImage.getY()) - dragView.getHeight() / 2); + + putPaneCenterAtWorldPos(citizenImage, playerPos); dragView.addChild(citizenImage); } @@ -341,7 +360,7 @@ private void updateBuildingView(final IBuildingView buildingView) this.buildings.put(buildingView, uiBuilding); } - uiBuilding.setPosition(worldPosToUIPos(buildingView.getID()).getX(), worldPosToUIPos(buildingView.getID()).getZ()); + putPaneCenterAtWorldPos(uiBuilding, buildingView.getID()); } /** @@ -357,7 +376,7 @@ private void addCitizens(final IColonyView colony) if (citizen != null) { final View citizenView = new View(); - citizenView.setPosition(worldPosToUIPos(citizen.blockPosition()).getX(), worldPosToUIPos(citizen.blockPosition()).getZ()); + putPaneCenterAtWorldPos(citizenView, citizen.blockPosition()); final Image citizenImage = new Image(); citizenImage.setImage(((ISimpleModelType) IModelTypeRegistry.getInstance().getModelType(citizen.getModelType())).getTextureIcon(citizen), false); @@ -369,7 +388,7 @@ private void addCitizens(final IColonyView colony) if (!data.getJob().isEmpty()) { citizenImage.setSize(8, 8); - builder.newLine().append(Component.translatableEscape("com.minecolonies.coremod.gui.citizen.job.label", LanguageHandler.format(data.getJob()))); + builder.newLine().append(Component.translatableEscape("com.minecolonies.coremod.gui.citizen.job.label", Component.translatable(data.getJob()))); } builder.color(COLOR_TEXT_FULFILLED).build(); citizenView.setSize(citizenImage.getWidth(), citizenImage.getHeight()); @@ -393,24 +412,28 @@ private void addCitizens(final IColonyView colony) } } - /** - * Scales the world pos to the UI pos, current scales positions which are farther out to display closer so you get a decent overview of nearby colonies which can be quite far away - * - * @param worldPos - * @return - */ - private BlockPos worldPosToUIPos(final BlockPos worldPos) + private void putPaneTopLeftCornerAtWorldPos(final Pane pane, final BlockPos worldPos) { - return BlockPos.containing( - dragView.getWidth() / 2.0 - ((playerPos.getX() - worldPos.getX()) * 4 / Math.max(1, Math.log(Math.abs(playerPos.getX() - worldPos.getX()) / 1000f))) * currentScale, - 0, - dragView.getHeight() / 2.0 - ((playerPos.getZ() - worldPos.getZ()) * 4 / Math.max(1, Math.log(Math.abs(playerPos.getZ() - worldPos.getZ()) / 1000f))) * currentScale); + applyWorldPosToPane(pane, worldPos, 0, 0); } - @Override - public void onClosed() + private void putPaneCenterAtWorldPos(final Pane pane, final BlockPos worldPos) { - super.onClosed(); - maps.forEach(MinecraftMap::close); + applyWorldPosToPane(pane, worldPos, -pane.getWidth() / 2, -pane.getHeight() / 2); + } + + private void applyWorldPosToPane(final Pane pane, final BlockPos worldPos, final int offsetUiX, final int offsetUiZ) + { + // vector from player pos + int x = worldPos.getX() - worldPosRoot.getX(); + int z = worldPos.getZ() - worldPosRoot.getZ(); + + x *= MAP_ZOOM; + z *= MAP_ZOOM; + + x += offsetUiX; + z += offsetUiZ; + + pane.setPosition(x, z); } } diff --git a/src/main/java/com/minecolonies/core/colony/buildings/workerbuildings/BuildingTownHall.java b/src/main/java/com/minecolonies/core/colony/buildings/workerbuildings/BuildingTownHall.java index 675b4b8291d..a9b1621e6b8 100755 --- a/src/main/java/com/minecolonies/core/colony/buildings/workerbuildings/BuildingTownHall.java +++ b/src/main/java/com/minecolonies/core/colony/buildings/workerbuildings/BuildingTownHall.java @@ -9,6 +9,7 @@ import com.minecolonies.api.colony.buildings.modules.settings.ISettingKey; import com.minecolonies.api.colony.buildings.workerbuildings.ITownHall; import com.minecolonies.api.colony.buildings.workerbuildings.ITownHallView; +import com.minecolonies.api.colony.buildings.workerbuildings.ITownHallView.MapEntry; import com.minecolonies.api.colony.colonyEvents.descriptions.IColonyEventDescription; import com.minecolonies.api.colony.colonyEvents.registry.ColonyEventDescriptionTypeRegistryEntry; import com.minecolonies.api.colony.permissions.PermissionEvent; @@ -23,13 +24,14 @@ import com.minecolonies.core.colony.buildings.modules.settings.SettingKey; import com.minecolonies.core.colony.buildings.views.AbstractBuildingView; import net.minecraft.core.BlockPos; -import net.minecraft.nbt.CompoundTag; +import net.minecraft.core.component.DataComponents; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.item.MapItem; import net.minecraft.world.level.Level; +import net.minecraft.world.level.saveddata.maps.MapId; import net.minecraft.world.level.saveddata.maps.MapItemSavedData; import org.jetbrains.annotations.NotNull; @@ -173,15 +175,16 @@ public void serializeToView(@NotNull final RegistryFriendlyByteBuf buf, final bo final Level level = colony.getWorld(); - final List mapDataList = new ArrayList<>(); + final List mapDataList = new ArrayList<>(); for (final ItemStack stack : maps) { try { + final MapId mapId = stack.get(DataComponents.MAP_ID); final MapItemSavedData mapData = MapItem.getSavedData(stack, level); - if (mapData != null) + if (mapData != null && mapData.scale == 0) { - mapDataList.add(mapData); + mapDataList.add(new MapEntry(mapId, mapData)); } } catch (final Exception ex) @@ -191,9 +194,9 @@ public void serializeToView(@NotNull final RegistryFriendlyByteBuf buf, final bo } buf.writeInt(mapDataList.size()); - for (final MapItemSavedData mapData : mapDataList) + for (final MapEntry mapData : mapDataList) { - buf.writeNbt(mapData.save(new CompoundTag(), buf.registryAccess())); + MapEntry.STREAM_CODEC.encode(buf, mapData); } } @@ -247,7 +250,7 @@ public static class View extends AbstractBuildingView implements ITownHallView /** * List of mapdata. */ - private List mapDataList = new ArrayList<>(); + private List mapDataList = new ArrayList<>(); /** * Instantiates the view of the building. @@ -302,8 +305,7 @@ public void deserialize(@NotNull final RegistryFriendlyByteBuf buf) mapDataList.clear(); for (int i = 0; i < size; i++) { - final MapItemSavedData mapData = MapItemSavedData.load(buf.readNbt(), buf.registryAccess()); - mapDataList.add(mapData); + mapDataList.add(MapEntry.STREAM_CODEC.decode(buf)); } } @@ -325,11 +327,8 @@ public boolean canPlayerUseTP() return canPlayerUseTP; } - /** - * Getter for the mapdata. - * @return the original list. - */ - public List getMapDataList() + @Override + public List getMapDataList() { return mapDataList; } diff --git a/src/main/java/com/minecolonies/core/generation/ItemNbtCalculator.java b/src/main/java/com/minecolonies/core/generation/ItemNbtCalculator.java index 629a3dfedb1..076f4169398 100644 --- a/src/main/java/com/minecolonies/core/generation/ItemNbtCalculator.java +++ b/src/main/java/com/minecolonies/core/generation/ItemNbtCalculator.java @@ -23,6 +23,7 @@ import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.CreativeModeTab; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; import org.jetbrains.annotations.NotNull; import java.nio.file.Path; @@ -84,6 +85,7 @@ public CompletableFuture run(@NotNull final CachedOutput cache) } }); + listBuilder.add(Items.FILLED_MAP.getDefaultInstance()); allStacks = listBuilder.build(); final TreeMap> keyMapping = new TreeMap<>(); @@ -109,6 +111,10 @@ public CompletableFuture run(@NotNull final CachedOutput cache) { keys.add(DataComponents.DYED_COLOR); } + if (stack.is(Items.FILLED_MAP)) + { + keys.add(DataComponents.MAP_ID); + } if (!stack.isEnchantable()) { keys.remove(DataComponents.ENCHANTMENTS); diff --git a/src/main/resources/assets/minecolonies/lang/manual_en_us.json b/src/main/resources/assets/minecolonies/lang/manual_en_us.json index f348f125b92..f722f99efdf 100644 --- a/src/main/resources/assets/minecolonies/lang/manual_en_us.json +++ b/src/main/resources/assets/minecolonies/lang/manual_en_us.json @@ -2485,8 +2485,6 @@ "com.minecolonies.coremod.gui.interval.lastweek": "Last Week", "com.minecolonies.coremod.gui.interval.100days": "Last 100 Days", "com.minecolonies.coremod.gui.interval.alltime": "All Time", - "com.minecolonies.coremod.gui.townhall.stats.items_delivered": "Delivered Items: %d", - "com.minecolonies.coremod.gui.townhall.stats.food_served": "Served Food: %d", "com.minecolonies.coremod.gui.townHall.map": "Town Map", "com.minecolonies.coremod.townhall.map.warning": "Drop-off a normal scale Minecraft map in the Town Hall inventory first to unlock the map.", "com.minecolonies.gui.edit": "Edit",