介绍
Dynmap 是 Minecraft 中以网页 Web 形式呈现地图的模组,和 BlueMap 等类似。我自己倒是 Dynmap 用多了感觉更习惯一些就一直用下去了,虽然如今 BlueMap 之类的确实更先进。
LiveAtlas
LiveAtlas 是 Dynmap 的第三方皮肤扩展,下载好后直接导入 dynmap/web 文件夹覆盖即可。
配置
这是下载后的文件结构,从 repo 来看这个项目用的 Yarn + Vue,打开 index.html 看看。
<!DOCTYPE html>
<html lang="en"><head><meta charset="utf-8"><link rel="preload" href="https://fonts.gstatic.com/s/raleway/v22/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVvaorCIPrE.woff2" as="font" crossorigin="anonymous"><link rel="preload" href="https://fonts.gstatic.com/s/raleway/v22/1Ptxg8zYS_SKggPN4iEgvnHyvveLxVsEpbCIPrE.woff2" as="font" crossorigin="anonymous"><meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no"><meta name="apple-mobile-web-app-capable" content="yes" /><meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" /><meta name="theme-color" content="#222222"><link rel="manifest" href="./live-atlas/favicons/site.webmanifest"><link rel="icon" href="./live-atlas/favicons/favicon.svg"><link rel=”mask-icon” href="./live-atlas/favicons/mask.svg" color="#cccccc"><link rel="apple-touch-icon" sizes="180x180" href="./live-atlas/favicons/apple-touch-icon.png"><meta name="keywords" content="minecraft, map, dynamic, liveatlas" /><meta name="description" content="Minecraft Dynamic Map" /><title>Minecraft Dynamic Map - LiveAtlas</title><!-- Remove this if you are using the servers config below --><script src="./standalone/config.js"></script><script>window.liveAtlasConfig = {// By default LiveAtlas looks for a dynmap standalone/config.js file// This configuration can be used instead to support Pl3xmap and Squaremap installations as well as multiple servers (external webserver required)// To configure multiple servers, see https://github.com/JLyne/LiveAtlas/wiki/Configuring-Multiple-Servers.// Example Squaremap internal webserver configuration// servers: {// squaremap: {// squaremap: window.location.pathname// },// },// Example Pl3xmap internal webserver configuration// servers: {// pl3xmap: {// pl3xmap: window.location.pathname// },// },// Example Overviewer configuration// servers: {// overviewer: {// overviewer: window.location.pathname// },// },// Example Dynmap internal webserver configuration without using standalone/config.js// servers: {// dynmap: {// dynmap: {// configuration: 'standalone/dynmap_config.json?_={timestamp}',// update: 'standalone/dynmap_{world}.json?_={timestamp}',// sendmessage: 'standalone/sendmessage.php',// login: 'standalone/login.php',// register: 'standalone/register.php',// tiles: 'tiles/',// markers: 'tiles/'// }// },// },// Example multiple Dynmap servers on external webserver configuration// servers: {// creative: {// label: 'Creative',// dynmap: {// configuration: 'http://dynmap.local/standalone/creative/MySQL_configuration.php',// update: 'http://dynmap.local/standalone/creative/MySQL_update.php?world={world}&ts={timestamp}',// sendmessage: 'http://dynmap.local/standalone/creative/MySQL_sendmessage.php',// login: 'http://dynmap.local/standalone/creative/MySQL_login.php',// register: 'http://dynmap.local/standalone/creative/MySQL_register.php',// tiles: 'http://dynmap.local/standalone/creative/MySQL_tiles.php?tile=',// markers: 'http://dynmap.local/standalone/creative/MySQL_markers.php?marker='// }// },// survival: {// label: 'Survival',// dynmap: {// configuration: 'http://dynmap.local/standalone/survival/MySQL_configuration.php',// update: 'http://dynmap.local/standalone/survival/MySQL_update.php?world={world}&ts={timestamp}',// sendmessage: 'http://dynmap.local/standalone/survival/MySQL_sendmessage.php',// login: 'http://dynmap.local/standalone/survival/MySQL_login.php',// register: 'http://dynmap.local/standalone/survival/MySQL_register.php',// tiles: 'http://dynmap.local/standalone/survival/MySQL_tiles.php?tile=',// markers: 'http://dynmap.local/standalone/survival/MySQL_markers.php?marker='// }// },// },// These messages are used throughout LiveAtlas and can be translated here// If a message you want to translate isn't here, it is likely controlled by dynmap itself// see https://github.com/webbukkit/dynmap/wiki/Configuration.txtmessages: {chatNoMessages: 'No chat messages yet...',chatTitle: 'Chat',chatLogin: 'Please login to send chat messages',chatSend: 'Send',chatPlaceholder: 'Type your chat message here...',chatErrorUnknown: 'Unexpected error while sending chat message',chatErrorDisabled: 'Chat is not enabled',serversHeading: 'Servers',markersHeading: 'Markers',markersSearchPlaceholder: 'Search markers...',markersSkeleton: 'No markers exist for the current world',markersSetSkeleton: 'This marker set is empty',markersSearchSkeleton: 'No matching markers found',markersUnnamed: '(Unnamed marker)',worldsSkeleton: 'No maps have been configured',playersSkeleton: 'No players are currently online',playersTitle: 'Click to center on player\nDouble-click to follow player',playersTitleHidden: 'This player is currently hidden from the map\nDouble-click to follow player when they become visible',playersTitleOtherWorld: 'This player is in another world.\nClick to center on player\nDouble-click to follow player',playersSearchPlaceholder: 'Search players...',playersSearchSkeleton: 'No matching players found',followingHeading: 'Following',followingUnfollow: 'Unfollow',followingTitleUnfollow: 'Stop following this player',followingHidden: 'Currently hidden',linkTitle: 'Copy link to current location',loadingTitle: 'Loading...',locationRegion: 'Region',locationChunk: 'Chunk',contextMenuCopyLink: 'Copy link to here',contextMenuCenterHere: 'Center here',toggleTitle: 'Click to toggle this section',mapTitle: 'Map - Use the arrow keys to pan the map',layersTitle: 'Layers',copyToClipboardSuccess: 'Copied to clipboard',copyToClipboardError: 'Unable to copy to clipboard',loginTitle: 'Login/Register',loginHeading: 'Existing User',loginUsernameLabel: 'Username',loginPasswordLabel: 'Password',loginSubmit: 'Login',loginErrorUnknown: 'Unexpected error while logging in',loginErrorDisabled: 'Logging in is disabled on this server',loginErrorIncorrect: 'Incorrect username or password',loginSuccess: 'Logged in successfully',registerHeading: 'New User',registerDescription: `Enter your username and password, along with your registration code.You can get a registration code by running /dynmap webregister in-game.`,registerConfirmPasswordLabel: 'Confirm Password',registerCodeLabel: 'Registration Code',registerSubmit: 'Register',registerErrorUnknown: 'Unexpected error during registration',registerErrorDisabled: 'Registration is disabled on this server',registerErrorVerifyFailed: 'The entered passwords do not match',registerErrorIncorrect: 'Registration failed, please check the entered details are correct',logoutTitle: 'Logout',logoutErrorUnknown: 'Unexpected error while logging out',logoutSuccess: 'Logged out successfully',closeTitle: 'Close',showMore: 'Show more'},ui: {// If true, player markers will always be displayed in front of other marker typesplayersAboveMarkers: true,// Whether to enable the player list search boxplayersSearch: true,// Use more compact pre-2.0 player marker stylecompactPlayerMarkers: false,// Disable the map right click menudisableContextMenu: false,// Disable the markers button and listdisableMarkerUI: false,// Custom URL to redirect to when logging in is required// This URL will need to handle the login process and redirect users back to LiveAtlascustomLoginUrl: null},// Config version. Do not modify.version: 1};</script><style>/* Theme colours */:root {--background-base: #222222; /* Foreground UI elements */--background-dark: #121212; /* Body/Splash screen/Shadows */--background-light: #363636; /* Scrollbars/inputs */--background-error: #771616; /* Errors */--background-marker: var(--background-dark); /* Map markers */--background-disabled: #555555; /* Disabled controls */--background-hover: #363636; /* :hovered buttons/menu items */--background-active: #6d6d6d; /* Button :active */--background-selected: #BDBDBD; /* Selected buttons/menu items */--outline-focus: #eeeeee; /* :focus outline */--border-radius: 0.5rem;--border-color: #333333; /* Control borders */--border-error: #cc0e0e;--box-shadow: 2px 2px 0px #111111;--text-base: rgba(255, 255, 255, 0.7); /* Normal text */--text-emphasis: rgba(255, 255, 255, 0.87); /* Chat messages/:focus inputs */--text-subtle: rgba(255, 255, 255, 0.5); /* Skeletons/secondary text */--text-disabled: var(--text-subtle); /* Disabled controls */--text-marker: var(--text-base); /* Map markers */--text-hover: var(--text-base); /* Text in :hover buttons */--text-active: var(--text-base); /* Text in :active buttons */--text-selected: var(--background-base); /* Text in selected buttons */--text-shadow: 0.1rem 0.1rem #000000; /* Text in selected buttons */--text-night: #ddffff; /* Clock time at night */--text-day: #ffdd33; /* Clock time in day */}@keyframes fade {from {opacity: 0;}to {opacity: 1;}}* {scrollbar-width: thin;scrollbar-color: var(--background-light) transparent;}*:hover, *:focus-within {scrollbar-color: var(--background-hover) transparent;}*::-webkit-scrollbar {width: 0.7rem;}*::-webkit-scrollbar-track {background: transparent;}*::-webkit-scrollbar-thumb {background-color: var(--background-light);border: 2px solid #000000;border-radius: 2rem;transition: background 1s ease-in;padding-right: 0.2rem;}*:hover::-webkit-scrollbar-thumb, *:focus-within::-webkit-scrollbar-thumb {background-color: var(--background-hover);}*::-webkit-scrollbar-button {display: none;}html, body {background-color: var(--background-dark);height: 100%;width: 100%;margin: 0;padding: 0;overscroll-behavior: none;}html {font-size: 62.5%;}body {font-family: Raleway,system-ui,-apple-system,'Segoe UI',Roboto,Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji';color: var(--text-base);text-shadow: var(--text-shadow);letter-spacing: 0.02rem;}noscript {color: var(--text-base);font-size: 1rem;font-family: sans-serif;text-align: center;line-height: 1.25;}#splash, noscript {position: fixed;top: 0;left: 0;bottom: 0;right: 0;transition: 0.3s opacity linear;z-index: 100;background-color: var(--background-dark);cursor: wait;display: flex;flex-direction: column;align-items: center;justify-content: center;font-size: 1.6rem;padding: 4rem;}#splash[hidden] {display: none;}#splash__spinner {margin-top: 4rem;animation: fade 0.5s linear 1s;animation-fill-mode: both;}#splash__error {margin-top: 2rem;transition: opacity 0.5s ease-in;display: flex;flex-direction: column;text-align: center;max-width: 60rem;}#splash__error-message {font-family: monospace;background-color: var(--background-error);padding: 1rem 1.5rem;border-radius: var(--border-radius);margin-bottom: 1rem;}#splash__error[aria-hidden=true] {opacity: 0;}#app {font-size: 1.6rem;height: 100%;}</style><script type="module" crossorigin src="./live-atlas/assets/index.a82d2095.js"></script><link rel="modulepreload" href="./live-atlas/assets/vendor.d0ab50b1.js"><link rel="stylesheet" href="./live-atlas/assets/index.1de34b3a.css"></head><body><div id="splash"><svg id="splash__logo" width="200" height="200" viewBox="0 0 268.83 266.53" aria-hidden="true" fill="rgba(255, 255, 255, 0.7)"><path d="M5.235.662C2.153.606 0 2.945 0 6.912v216.577c0 5.288 3.828 11.41 8.582 13.725l57.835 28.165c4.755 2.316 8.582-.078 8.582-5.367V43.434c0-5.288-3.827-11.41-8.582-13.727L8.582 1.544C7.394.965 6.262.681 5.235.662zm32.283 135.96c14.394 0 26.062 11.669 26.062 26.063 0 14.394-24.167 59.55-26.062 57.654-1.854 1.854-26.063-43.26-26.063-57.654 0-14.394 11.669-26.063 26.063-26.063zM202.388 1.013l57.833 28.165c4.755 2.315 8.583 8.437 8.583 13.726v216.58c0 5.29-3.828 7.683-8.583 5.367l-57.833-28.164c-4.755-2.316-8.583-8.438-8.583-13.727V6.38c0-5.289 3.828-7.682 8.583-5.367zM172.012.39c-1.051-.035-2.209.191-3.426.709l-68.342 29.053c-4.867 2.07-8.786 7.993-8.786 13.282V260.01c0 5.29 3.919 7.88 8.786 5.811l68.342-29.053c4.867-2.07 8.786-7.991 8.786-13.28V6.91c0-3.967-2.204-6.417-5.36-6.521zm-36.949 41.216c14.394 0 26.063 11.668 26.063 26.062 0 14.394-24.168 59.55-26.063 57.655C133.209 127.177 109 82.063 109 67.668c0-14.394 11.669-26.062 26.063-26.062z"/><path d="M48.573 162.689a11.056 11.056 0 0 1-11.056 11.056 11.056 11.056 0 0 1-11.056-11.056 11.056 11.056 0 0 1 11.056-11.056 11.056 11.056 0 0 1 11.056 11.056zM146.12 67.669a11.056 11.056 0 0 1-11.057 11.056 11.056 11.056 0 0 1-11.056-11.056 11.056 11.056 0 0 1 11.056-11.056 11.056 11.056 0 0 1 11.056 11.056z"/></svg><svg id="splash__spinner" width="38" height="38" viewBox="0 0 38 38" stroke="#fff" aria-label="LiveAtlas is loading"><g transform="translate(1 1)" stroke-width="2" fill="none"><circle stroke-opacity=".5" cx="18" cy="18" r="18"/><path d="M36 18c0-9.94-8.06-18-18-18"><animateTransform attributeName="transform" type="rotate" from="0 18 18" to="360 18 18" dur="1s" repeatCount="indefinite"/></path></g></svg><div id="splash__error" aria-hidden="true"><span id="splash__error-message" role="alert"></span><span id="splash__error-retry" aria-live="polite"></span></div></div><noscript><strong>LiveAtlas requires JavaScript to work.<br />Please enable it to continue.</strong></noscript><main id="app" aria-hidden="true"></main><script>window.addEventListener('load', () => {if(!window.liveAtlasLoaded) {document.getElementById('splash__error').setAttribute('aria-hidden', 'false');document.getElementById('splash__error-message').innerText = 'Required LiveAtlas files are missing or failed to load.\nPlease reinstall LiveAtlas.';document.getElementById('splash__spinner').style.visibility = 'hidden';}});</script></body>
</html>
index.html 里面的内容都预留好了配置口,比如翻译信息、CSS,需要的话直接覆盖修改即可。以下是笔者自己的翻译信息:
messages: {chatNoMessages: '没人发信息喵。',chatTitle: '聊天',chatLogin: '只有登录了才能发消息喵~',chatSend: '发送',chatPlaceholder: '聊天信息输在这',chatErrorUnknown: '不知道为什么消息发不出去',chatErrorDisabled: '聊天未启用',serversHeading: '服务器',markersHeading: '标记',markersSearchPlaceholder: '搜索标记',markersSkeleton: '当前世界没有标记点存在',markersSetSkeleton: '这个标记点是空的',markersSearchSkeleton: '无匹配结果',markersUnnamed: '(未命名标记)',worldsSkeleton: '没有地图被配置',playersSkeleton: '现在没人在线喵!',playersTitle: '单击以定位玩家\n双击以跟随玩家',playersTitleHidden: '该玩家在当前地图上隐藏\n双击可在玩家可见时跟随',playersTitleOtherWorld: '该玩家在另一个世界\n点击以定位到玩家\n双击以跟随玩家',playersSearchPlaceholder: '搜索玩家…',playersSearchSkeleton: '找不到匹配的玩家',followingHeading: '跟随中',followingUnfollow: '取消跟随',followingTitleUnfollow: '停止跟随该玩家',followingHidden: '当前隐藏',linkTitle: '获取当前坐标的网址',loadingTitle: '加载中…',locationRegion: '区域',locationChunk: '区块',contextMenuCopyLink: '复制链接',contextMenuCenterHere: '定位到此处',toggleTitle: '点击以切换此部分',mapTitle: '地图 - 使用方向键移动地图',layersTitle: '图层',copyToClipboardSuccess: '已复制到剪贴板',copyToClipboardError: '无法复制到剪贴板',loginTitle: '登录',loginHeading: '已有账户登录',loginUsernameLabel: '用户名',loginPasswordLabel: '密码',loginSubmit: '登录',loginErrorUnknown: '登录时出现未知错误',loginErrorDisabled: '登录已禁用',loginErrorIncorrect: '用户名或密码错误',loginSuccess: '登录成功喵!!',registerHeading: '新用户注册',registerDescription: `分别输入你的用户名、密码和注册码喵!注册码需要在服务器中获取。在游戏中输入/dynmap webregister可以获得注册码。`,registerConfirmPasswordLabel: '确认密码',registerCodeLabel: '注册码',registerSubmit: '注册',registerErrorUnknown: '注册时出现未知错误',registerErrorDisabled: '注册已禁用',registerErrorVerifyFailed: '前后输入的密码不一致,笨蛋。',registerErrorIncorrect: '注册失败了,检查下输入内容的是否有误喵',logoutTitle: '登出',logoutErrorUnknown: '登出时出现未知错误',logoutSuccess: '已登出',closeTitle: '关闭',showMore: '显示更多'}
CSS 也是按需修改,笔者还是比较喜欢浅色的()所以自己的几个站点风格都比较接近,感兴趣的可以去 repo 看代码。
CDN
笔者给卫星地图配置的域名是通过 CDN 的,服务商是腾讯云,反代总担心性能和带宽都不够,而且每次这么多图片请求压力也比较大,考虑到卫星地图看的人不多就上了 CDN。腾讯云国内流量是 19 元 100 G,用个半年没啥问题,每天顶多 100 M()