Lots of layout changes.

Add placeholders for future functions.
Add buttons for install, update, update mods, etc.
Add bootstrap icons CDN.
Remove old CSS in favor of Bootstrap classes.
Add favico.
Update docs.
This commit is contained in:
Daniel Ceregatti 2023-05-26 22:59:36 -07:00
parent 8a8dc7f25a
commit 052304f450
6 changed files with 170 additions and 70 deletions

View file

@ -18,6 +18,10 @@ This volume can get quite large. It will require at least 2G of disk space for t
Some map mods are as large as 10G. Make sure you have that much disk space in the location where docker stores its
volumes, usually `/var/lib/docker/volumes`.
## Goals
* Provide a turnkey DayZ server with mod support.
## Configure and Build
Ensure [Docker](https://docs.docker.com/engine/install/) and [Docker compose](https://docs.docker.com/compose/install/)
@ -152,7 +156,7 @@ docker compose exec main dayzserver force
When the server exits cleanly, i.e. exit code 0, the container also stops. Otherwise, a crash is presumed, and the server will be restarted.
NOTE: As DayZ Experimental 1.19, the server is known to not exit upon SIGINT when mods are installed. This makes force stopping the server
required. This is not a clean exit, and will cause the server to restart. Manually take the server [down](#down) to stop the container.
required. This is not a clean exit, and will cause the server to restart. Manually take the server [down](#stop) to stop the container.
### Workshop - Add / List / Remove / Update mods

BIN
web/root/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

View file

@ -1,23 +1,15 @@
body {
padding-top: 10px;
padding: 10px;
background-color: black;
}
.green {
color: green;
font-weight: bolder;
}
.yellow {
color: yellow;
font-weight: bolder;
}
.darkgrey {
background-color: darkgray;
font-weight: bolder;
margin-bottom: 10px;
button {
padding: 5px;
margin: 10px;
}
.modInfo {
background-color: aliceblue;
th, td {
padding-right: 10px
}
.result {
@ -32,7 +24,3 @@ body {
cursor: pointer;
text-underline: blue;
}
th, td {
padding-right: 10px
}

View file

@ -3,9 +3,10 @@
<head>
<meta charset="UTF-8">
<title>DayZ Docker Server</title>
<link rel="icon" type="image/x-icon" href="/favicon.png">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<link rel="stylesheet" href="/index.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.3.0/font/bootstrap-icons.css"> <link rel="stylesheet" href="/index.css">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>

View file

@ -1,31 +1,48 @@
const template = `
<div class="container-fluid">
<div class="row jumbotron darkgrey">
<div class="col-7">
<h1>DayZ Docker Server</h1>
<div class="container-fluid bg-light">
<div class="d-flex justify-content-between">
<div class="text-center">
<h1>DayZ Docker Server</h1>
</div>
<div class="d-flex">
<div class="text-center">
<button
@click="install"
:class="'btn ' + (installed ? 'btn-danger' : 'btn-success')"
>
Install Server Files
</button>
<button @click="updatebase" class="btn btn-warning">Update Base</button>
<button @click="updatemods" class="btn btn-warning">Update Mods</button>
</div>
<div class="text-center">
<button @click="server" class="btn btn-primary">Server</button>
</div>
</div>
<div class="col-3 form-control-lg">
<div class="form-control-lg">
<form @submit="handleSubmit">
<input name="search" placeholder="Search mods..." autofocus>
</form>
</div>
<div class="col-2">
<div>
Server files installed: {{ installed }}
<div>
<div class="justify-right">
Server files installed:
<span class="bi bi-check h2 text-success" v-if="installed"></span>
<span class="bi bi-x h2 danger text-danger" v-else></span>
</div>
<div>
Version: {{ version }}
<div v-if="version != ''">
Version: <span class="text-success font-weight-bold">{{ version }}</span>
</div>
</div>
</div>
<div
v-if="fetchError != ''"
class="row jumbotron text-center alert alert-danger"
class="text-center alert alert-danger"
>
{{ fetchError }}
</div>
<div class="row jumbotron darkgrey">
<div class="col-3">
<div class="d-flex">
<div>
<h2 class="text-center">Mods</h2>
<table>
<tr>
@ -39,7 +56,7 @@ const template = `
<td>
<a
target="_blank"
:href="'https://steamcommunity.com/sharedfiles/filedetails/?id=' + mod.id"
:href="steamURL + mod.id"
>
{{ mod.id }}
</a>
@ -51,7 +68,40 @@ const template = `
</template>
</table>
</div>
<div class="col-9 modInfo" v-if="searchResults != ''">
<div v-if="modInfo != ''">
<div>
<h3>{{ modInfo.name }}</h3>
<div class="d-flex">
<div>
<div>
ID: {{ modInfo.id }}
</div>
<div>
Size: {{ modInfo.size.toLocaleString("en-US") }}
</div>
<div v-if="modInfo.customXML.length > 0">
Custom XML files:
<ul>
<li v-for="info in modInfo.customXML">
<a
:class="'simulink xmlfile ' + info.name"
@click="getXMLInfo(modInfo.id,info.name)"
>
{{ info.name }}
</a>
</li>
</ul>
</div>
</div>
<div>
<div v-if="XMLInfo != ''">
<textarea cols="120" rows="15" v-if="this.XMLInfo != ''">{{ this.XMLInfo }}</textarea>
</div>
</div>
</div>
</div>
</div>
<div v-if="searchResults != ''">
<table>
<tr>
<th>Steam Link</th>
@ -65,9 +115,9 @@ const template = `
<td>
<a
target="_blank"
:href="'https://steamcommunity.com/sharedfiles/filedetails/?id=' + result.publishedfileid"
:href="steamURL + result.publishedfileid"
>
<img data-bs-toggle="tooltip" data-bs-placement="left" :title="result.short_description" width="160" height="90" :src="result.preview_url">
<img :alt="result.short_description" data-bs-toggle="tooltip" data-bs-placement="left" :title="result.short_description" width="160" height="90" :src="result.preview_url">
</a>
</td>
<td>{{ result.title }}</td>
@ -81,37 +131,6 @@ const template = `
</tr>
</table>
</div>
<div class="col-9 modInfo" v-if="modInfo != ''">
<div class="text-center col-12">
<h2>{{ modInfo.name }} mod info:</h2>
</div>
<div class="row">
<div class="col-2">
<div>
ID: {{ modInfo.id }}
</div>
<div>
Size: {{ modInfo.size.toLocaleString("en-US") }}
</div>
<div v-if="modInfo.customXML.length > 0">
Custom XML files:
<ul>
<li v-for="info in modInfo.customXML">
<a
:class="'simulink xmlfile ' + info.name"
@click="getXMLInfo(modInfo.id,info.name)"
>
{{ info.name }}
</a>
</li>
</ul>
</div>
</div>
<div class="col-10">
<textarea cols="120" rows="15" v-if="this.XMLInfo != ''">{{ this.XMLInfo }}</textarea>
</div>
</div>
</div>
</div>
</div>
`
@ -126,6 +145,7 @@ export default {
mods: [],
modInfo: "",
searchResults: [],
steamURL: 'https://steamcommunity.com/sharedfiles/filedetails/?id=',
version: "Unknown",
XMLFile: "",
XMLInfo: "",
@ -196,6 +216,17 @@ export default {
this.fetchError = error.message
})
},
removeMod(modId) {
fetch('/remove/' + modId)
.then(response => response.text())
.then(response => {
console.log(response)
})
.catch((error) => {
console.error(error)
this.fetchError = error.message
})
},
BKMG(val) {
const units = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
let l = 0, n = parseInt(val, 10) || 0

View file

@ -1,3 +1,11 @@
/*
A DayZ Linux server provisioning system.
This is the web UI for provisioning a DayZ server running under Linux.
It manages the main container that installs and maintains the base DayZ server files
along with all mod base files. The goal being to keep all of these centralized and consistent,
but to also make them available for the creation of server containers.
*/
import express from 'express'
import path from 'path'
import fs from 'fs'
@ -45,6 +53,49 @@ const configFiles = [
'types.xml',
]
// From https://helpthedeadreturn.wordpress.com/2019/07/17/dayz-sa-mission-file
const allConfigFiles = {
"db": [ // global server config and core loot economy files
"events.xml", // dynamic events
"globals.xml", // global settings
"messages.xml", // server broadcast messages and shutdown
"types.xml" // loot table
],
"env": [ // coordinates, static and dynamic spawns for each entity
"cattle_territories.xml",
"domestic_animals_territories.xml",
"hare_territories.xml",
"hen_territories.xml",
"pig_territories.xml",
"red_deer_territories.xml",
"roe_deer_territories.xml",
"sheep_goat_territories.xml",
"wild_boar_territories.xml",
"wolf_territories.xml",
"zombie_territories.xml"
],
"root": [
"cfgeconomycore.xml", // loot economy core settings and extensions
"cfgeffectarea.json", // static contaminated area coordinates and other properties
"cfgenvironment.xml", // includes env\* files and parameters
"cfgeventgroups.xml", // definitions of groups of objects that spawn together in a dynamic event
"cfgeventspawns.xml", // coordinates where events may occur
"cfggameplay.json", // gameplay configuration settings.
"cfgIgnoreList.xml", // list of items that wont be loaded from the storage
"cfglimitsdefinition.xml", // list of valid categories, tags, usageflags and valueflags
"cfglimitsdefinitionuser.xml", // shortcut groups of usageflags and valueflags
"cfgplayerspawnpoints.xml", // new character spawn points
"cfgrandompresets.xml", // collection of groups of items
"cfgspawnabletypes.xml", // loot categorization (ie hoarder) as well as set of items that spawn as cargo or as attachment on weapons, vehicles or infected.
"cfgundergroundtriggers.json", // used for triggering light and sounds in the Livonia bunker, not used for Chernarus
"cfgweather.xml", // weather configuration
"init.c", // mission startup file (PC only)
"map*.xml",
"mapgroupproto.xml", // structures, tags, maxloot and lootpoints
"mapgrouppos.xml" // all valid lootpoints
]
}
const config = {
installFile: serverFiles + "/DayZServer",
modDir: modDir + "/" + client_appid,
@ -52,6 +103,13 @@ const config = {
steamAPIKey: process.env["STEAMAPIKEY"]
}
const getVersion = (installed) => {
if(installed) {
return "1.20.bogus"
}
return ""
}
const getDirSize = (dirPath) => {
let size = 0
const files = fs.readdirSync(dirPath)
@ -144,6 +202,23 @@ app.get(('/install/:modId'), (req, res) => {
res.send(modId + " was installed")
})
// Remove a mod
app.get(('/remove/:modId'), (req, res) => {
const modId = req.params["modId"]
// Shell out to steamcmd, monitor the process, and display the output as it runs
res.send(modId + " was removed")
})
// Update base files
app.get('/updatebase', (req, res) => {
res.send("Base files were updates")
})
// Update mods
app.get('/updatemods', (req, res) => {
res.send("Mod files were updates")
})
/*
Get the status of things:
If the base files are installed, the version of the server, a list of mods, etc.
@ -152,9 +227,10 @@ app.get('/status', (req, res) => {
// FIXME Async/await this stuff...
const installed = fs.existsSync(config.installFile)
const mods = getMods()
const version = getVersion(installed)
const ret = {
"installed": installed,
"version": "1.20.bogus",
"version": version,
"mods": mods
}
res.send(ret)