You've already forked factorio-server-manager
mirror of
https://github.com/OpenFactorioServerManager/factorio-server-manager.git
synced 2025-07-15 01:14:28 +02:00
Merge pull request #94 from knoxfighter/feature/mod-compatibility
Feature/mod compatibility
This commit is contained in:
@ -12,6 +12,7 @@ install:
|
|||||||
- go get github.com/hpcloud/tail
|
- go get github.com/hpcloud/tail
|
||||||
- go get github.com/gorilla/websocket
|
- go get github.com/gorilla/websocket
|
||||||
- go get github.com/majormjr/rcon
|
- go get github.com/majormjr/rcon
|
||||||
|
- go get github.com/Masterminds/semver
|
||||||
- export GOPATH="$HOME/gopath/src/github.com/mroote/factorio-server-manager/:$GOPATH"
|
- export GOPATH="$HOME/gopath/src/github.com/mroote/factorio-server-manager/:$GOPATH"
|
||||||
|
|
||||||
script:
|
script:
|
||||||
|
@ -145,6 +145,7 @@ go get github.com/gorilla/mux
|
|||||||
go get github.com/hpcloud/tail
|
go get github.com/hpcloud/tail
|
||||||
go get github.com/gorilla/websocket
|
go get github.com/gorilla/websocket
|
||||||
go get github.com/majormjr/rcon
|
go get github.com/majormjr/rcon
|
||||||
|
go get github.com/Masterminds/semver
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Now you will want to go into the src folder for example "C:\FS\factorio-server-manager\src" once there hold down left shift and right click an empty area of the folder. Then click "Open command windows here"
|
3. Now you will want to go into the src folder for example "C:\FS\factorio-server-manager\src" once there hold down left shift and right click an empty area of the folder. Then click "Open command windows here"
|
||||||
|
@ -69,5 +69,12 @@ div.console-prompt-box {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.sweet-alert table tr:nth-child(even) {
|
.sweet-alert table tr:nth-child(even) {
|
||||||
background: rgba(68, 68, 68, 0.31);
|
background: rgba(68, 68, 68, 0.21);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sweet-alert table tr.incompatible {
|
||||||
|
background: rgba(255, 68, 68, 0.21);
|
||||||
|
}
|
||||||
|
.sweet-alert table tr:nth-child(even).incompatible {
|
||||||
|
background: rgba(255, 0, 0, 0.31);
|
||||||
}
|
}
|
@ -4,3 +4,4 @@ github.com/gorilla/mux
|
|||||||
github.com/gorilla/websocket
|
github.com/gorilla/websocket
|
||||||
github.com/hpcloud/tail
|
github.com/hpcloud/tail
|
||||||
github.com/majormjr/rcon
|
github.com/majormjr/rcon
|
||||||
|
github.com/Masterminds/semver
|
@ -17,21 +17,26 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/majormjr/rcon"
|
"github.com/majormjr/rcon"
|
||||||
|
"regexp"
|
||||||
|
"github.com/Masterminds/semver"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FactorioServer struct {
|
type FactorioServer struct {
|
||||||
Cmd *exec.Cmd `json:"-"`
|
Cmd *exec.Cmd `json:"-"`
|
||||||
Savefile string `json:"savefile"`
|
Savefile string `json:"savefile"`
|
||||||
Latency int `json:"latency"`
|
Latency int `json:"latency"`
|
||||||
BindIP string `json:"bindip"`
|
BindIP string `json:"bindip"`
|
||||||
Port int `json:"port"`
|
Port int `json:"port"`
|
||||||
Running bool `json:"running"`
|
Running bool `json:"running"`
|
||||||
StdOut io.ReadCloser `json:"-"`
|
Version string `json:"fac_version"`
|
||||||
StdErr io.ReadCloser `json:"-"`
|
BaseModVersion string `json:"base_mod_version"`
|
||||||
StdIn io.WriteCloser `json:"-"`
|
SemVerVersion *semver.Version `json:"-"`
|
||||||
Settings map[string]interface{} `json:"-"`
|
StdOut io.ReadCloser `json:"-"`
|
||||||
Rcon *rcon.RemoteConsole `json:"-"`
|
StdErr io.ReadCloser `json:"-"`
|
||||||
LogChan chan []string `json:"-"`
|
StdIn io.WriteCloser `json:"-"`
|
||||||
|
Settings map[string]interface{} `json:"-"`
|
||||||
|
Rcon *rcon.RemoteConsole `json:"-"`
|
||||||
|
LogChan chan []string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func randomPort() int {
|
func randomPort() int {
|
||||||
@ -92,6 +97,38 @@ func initFactorio() (f *FactorioServer, err error) {
|
|||||||
|
|
||||||
log.Printf("Loaded Factorio settings from %s\n", settingsPath)
|
log.Printf("Loaded Factorio settings from %s\n", settingsPath)
|
||||||
|
|
||||||
|
|
||||||
|
//Load factorio version
|
||||||
|
out, err := exec.Command(config.FactorioBinary, "--version").Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error on loading factorio version: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
reg := regexp.MustCompile("Version.*?((\\d+\\.)?(\\d+\\.)?(\\*|\\d+)+)")
|
||||||
|
found := reg.FindStringSubmatch(string(out))
|
||||||
|
f.Version = found[1]
|
||||||
|
|
||||||
|
//Load baseMod version
|
||||||
|
baseModInfoFile := filepath.Join(config.FactorioDir, "data", "base", "info.json")
|
||||||
|
bmifBa, err := ioutil.ReadFile(baseModInfoFile)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("couldn't open baseMods info.json: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var modInfo ModInfo
|
||||||
|
err = json.Unmarshal(bmifBa, &modInfo)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error unmarshalling baseMods info.json to a modInfo: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
f.BaseModVersion = modInfo.Version
|
||||||
|
f.SemVerVersion, err = semver.NewVersion(modInfo.Version)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("error loading semver-factorio-version: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -435,6 +435,24 @@ func CheckServer(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func FactorioVersion(w http.ResponseWriter, r *http.Request) {
|
||||||
|
resp := JSONResponse{
|
||||||
|
Success: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/json;charset=UTF-8")
|
||||||
|
|
||||||
|
status := map[string]string{}
|
||||||
|
status["version"] = FactorioServ.Version
|
||||||
|
status["base_mod_version"] = FactorioServ.BaseModVersion
|
||||||
|
|
||||||
|
resp.Data = status
|
||||||
|
|
||||||
|
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||||
|
log.Printf("Error loading Factorio Version: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func LoginUser(w http.ResponseWriter, r *http.Request) {
|
func LoginUser(w http.ResponseWriter, r *http.Request) {
|
||||||
resp := JSONResponse{
|
resp := JSONResponse{
|
||||||
Success: false,
|
Success: false,
|
||||||
|
@ -58,6 +58,7 @@ func (mods *Mods) listInstalledMods() ModsResultList {
|
|||||||
modsResult.Title = modInfo.Title
|
modsResult.Title = modInfo.Title
|
||||||
modsResult.Version = modInfo.Version
|
modsResult.Version = modInfo.Version
|
||||||
modsResult.FactorioVersion = modInfo.FactorioVersion
|
modsResult.FactorioVersion = modInfo.FactorioVersion
|
||||||
|
modsResult.Compatibility = modInfo.Compatibility
|
||||||
|
|
||||||
for _, simpleMod := range mods.ModSimpleList.Mods {
|
for _, simpleMod := range mods.ModSimpleList.Mods {
|
||||||
if simpleMod.Name == modsResult.Name {
|
if simpleMod.Name == modsResult.Name {
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ModInfoList struct {
|
type ModInfoList struct {
|
||||||
@ -17,12 +18,14 @@ type ModInfoList struct {
|
|||||||
Destination string `json:"-"`
|
Destination string `json:"-"`
|
||||||
}
|
}
|
||||||
type ModInfo struct {
|
type ModInfo struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Version string `json:"version"`
|
Version string `json:"version"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Author string `json:"author"`
|
Author string `json:"author"`
|
||||||
FileName string `json:"file_name"`
|
FileName string `json:"file_name"`
|
||||||
FactorioVersion string `json:"factorio_version"`
|
FactorioVersion string `json:"factorio_version"`
|
||||||
|
Dependencies []string `json:"dependencies"`
|
||||||
|
Compatibility bool `json:"compatibility"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newModInfoList(destination string) (ModInfoList, error) {
|
func newModInfoList(destination string) (ModInfoList, error) {
|
||||||
@ -46,6 +49,7 @@ func (modInfoList *ModInfoList) listInstalledMods() error {
|
|||||||
|
|
||||||
err = filepath.Walk(modInfoList.Destination, func(path string, info os.FileInfo, err error) error {
|
err = filepath.Walk(modInfoList.Destination, func(path string, info os.FileInfo, err error) error {
|
||||||
if !info.IsDir() && filepath.Ext(path) == ".zip" {
|
if !info.IsDir() && filepath.Ext(path) == ".zip" {
|
||||||
|
|
||||||
err = fileLock.RLock(path)
|
err = fileLock.RLock(path)
|
||||||
if err != nil && err == lockfile.ErrorAlreadyLocked {
|
if err != nil && err == lockfile.ErrorAlreadyLocked {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
@ -69,6 +73,29 @@ func (modInfoList *ModInfoList) listInstalledMods() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
modInfo.FileName = info.Name()
|
modInfo.FileName = info.Name()
|
||||||
|
|
||||||
|
var baseDependency string
|
||||||
|
for _, dependency := range modInfo.Dependencies {
|
||||||
|
if strings.HasPrefix(dependency, "base") {
|
||||||
|
baseDependency = strings.Split(dependency, "=")[1]
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if baseDependency != "" {
|
||||||
|
modInfo.Compatibility, err = checkModCompatibility(baseDependency)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error checking mod compatibility: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.Println("error finding basemodDependency. Using FactorioVersion...")
|
||||||
|
modInfo.Compatibility, err = checkModCompatibility(modInfo.FactorioVersion + ".0")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error checking Compatibility with FactorioVersion: %s", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
modInfoList.Mods = append(modInfoList.Mods, modInfo)
|
modInfoList.Mods = append(modInfoList.Mods, modInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
src/mods.go
21
src/mods.go
@ -12,6 +12,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"github.com/Masterminds/semver"
|
||||||
)
|
)
|
||||||
|
|
||||||
type LoginErrorResponse struct {
|
type LoginErrorResponse struct {
|
||||||
@ -274,9 +275,9 @@ func modStartUp() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
new_json, _ := json.Marshal(modSimpleList)
|
newJson, _ := json.Marshal(modSimpleList)
|
||||||
|
|
||||||
err = ioutil.WriteFile(modSimpleList.Destination+"/mod-list.json", new_json, 0664)
|
err = ioutil.WriteFile(modSimpleList.Destination+"/mod-list.json", newJson, 0664)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("error when writing new mod-list: %s", err)
|
log.Printf("error when writing new mod-list: %s", err)
|
||||||
return err
|
return err
|
||||||
@ -344,3 +345,19 @@ func modStartUp() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkModCompatibility(modVersion string) (compatible bool, err error) {
|
||||||
|
compatible = false
|
||||||
|
modVersion = strings.TrimSpace(modVersion)
|
||||||
|
if !strings.HasPrefix(modVersion, "~") {
|
||||||
|
modVersion = "~" + modVersion
|
||||||
|
}
|
||||||
|
|
||||||
|
constraint, err := semver.NewConstraint(modVersion)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("error loading constraint: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
return constraint.Check(FactorioServ.SemVerVersion), nil
|
||||||
|
}
|
||||||
|
@ -273,6 +273,11 @@ var apiRoutes = Routes{
|
|||||||
"GET",
|
"GET",
|
||||||
"/server/status",
|
"/server/status",
|
||||||
CheckServer,
|
CheckServer,
|
||||||
|
}, {
|
||||||
|
"FactorioVersion",
|
||||||
|
"GET",
|
||||||
|
"/server/facVersion",
|
||||||
|
FactorioVersion,
|
||||||
}, {
|
}, {
|
||||||
"LogoutUser",
|
"LogoutUser",
|
||||||
"GET",
|
"GET",
|
||||||
|
@ -15,9 +15,12 @@ class App extends React.Component {
|
|||||||
this.getSaves = this.getSaves.bind(this);
|
this.getSaves = this.getSaves.bind(this);
|
||||||
this.getStatus = this.getStatus.bind(this);
|
this.getStatus = this.getStatus.bind(this);
|
||||||
this.connectWebSocket = this.connectWebSocket.bind(this);
|
this.connectWebSocket = this.connectWebSocket.bind(this);
|
||||||
|
this.getFactorioVersion = this.getFactorioVersion.bind(this);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
serverRunning: "stopped",
|
serverRunning: "stopped",
|
||||||
serverStatus: {},
|
serverStatus: {},
|
||||||
|
factorioVersion: "",
|
||||||
saves: [],
|
saves: [],
|
||||||
loggedIn: false,
|
loggedIn: false,
|
||||||
username: "",
|
username: "",
|
||||||
@ -35,6 +38,7 @@ class App extends React.Component {
|
|||||||
}
|
}
|
||||||
}, 1000);
|
}, 1000);
|
||||||
this.connectWebSocket();
|
this.connectWebSocket();
|
||||||
|
this.getFactorioVersion(); //Init serverStatus, so i know, which factorio-version is installed
|
||||||
}
|
}
|
||||||
|
|
||||||
connectWebSocket() {
|
connectWebSocket() {
|
||||||
@ -55,8 +59,10 @@ class App extends React.Component {
|
|||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: (data) => {
|
success: (data) => {
|
||||||
if (data.success === true) {
|
if (data.success === true) {
|
||||||
this.setState({loggedIn: true,
|
this.setState({
|
||||||
username: data.data.Username})
|
loggedIn: true,
|
||||||
|
username: data.data.Username
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -67,7 +73,9 @@ class App extends React.Component {
|
|||||||
url: "/api/server/status",
|
url: "/api/server/status",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: (data) => {
|
success: (data) => {
|
||||||
this.setState({serverRunning: data.data.status})
|
this.setState({
|
||||||
|
serverRunning: data.data.status
|
||||||
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -98,7 +106,24 @@ class App extends React.Component {
|
|||||||
url: "/api/server/status",
|
url: "/api/server/status",
|
||||||
dataType: "json",
|
dataType: "json",
|
||||||
success: (data) => {
|
success: (data) => {
|
||||||
this.setState({serverStatus: data.data})
|
this.setState({
|
||||||
|
serverStatus: data.data
|
||||||
|
})
|
||||||
|
},
|
||||||
|
error: (xhr, status, err) => {
|
||||||
|
console.log('api/server/status', status, err.toString());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getFactorioVersion() {
|
||||||
|
$.ajax({
|
||||||
|
url: "/api/server/facVersion",
|
||||||
|
// dataType: "json",
|
||||||
|
success: (data) => {
|
||||||
|
this.setState({
|
||||||
|
factorioVersion: data.data.base_mod_version
|
||||||
|
});
|
||||||
},
|
},
|
||||||
error: (xhr, status, err) => {
|
error: (xhr, status, err) => {
|
||||||
console.log('api/server/status', status, err.toString());
|
console.log('api/server/status', status, err.toString());
|
||||||
@ -128,16 +153,19 @@ class App extends React.Component {
|
|||||||
// Render react-router components and pass in props
|
// Render react-router components and pass in props
|
||||||
{React.cloneElement(
|
{React.cloneElement(
|
||||||
this.props.children,
|
this.props.children,
|
||||||
{message: "",
|
{
|
||||||
messages: this.state.messages,
|
message: "",
|
||||||
flashMessage: this.flashMessage,
|
messages: this.state.messages,
|
||||||
facServStatus: this.facServStatus,
|
flashMessage: this.flashMessage,
|
||||||
serverStatus: this.state.serverStatus,
|
facServStatus: this.facServStatus,
|
||||||
getStatus: this.getStatus,
|
serverStatus: this.state.serverStatus,
|
||||||
saves: this.state.saves,
|
factorioVersion: this.state.factorioVersion,
|
||||||
getSaves: this.getSaves,
|
getStatus: this.getStatus,
|
||||||
username: this.state.username,
|
saves: this.state.saves,
|
||||||
socket: this.socket}
|
getSaves: this.getSaves,
|
||||||
|
username: this.state.username,
|
||||||
|
socket: this.socket
|
||||||
|
}
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import SemVer from 'semver';
|
||||||
|
|
||||||
class Mod extends React.Component {
|
class Mod extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -34,8 +35,20 @@ class Mod extends React.Component {
|
|||||||
dataType: "JSON",
|
dataType: "JSON",
|
||||||
success: (data) => {
|
success: (data) => {
|
||||||
let newData = JSON.parse(data.data);
|
let newData = JSON.parse(data.data);
|
||||||
let newestRelease = newData.releases[newData.releases.length - 1];
|
//get newest COMPATIBLE release
|
||||||
if(newestRelease.version != this.props.mod.version) {
|
let newestRelease;
|
||||||
|
newData.releases.forEach((release) => {
|
||||||
|
//TODO change to info_json dependency (when mod-portal-api is working again)
|
||||||
|
if(SemVer.satisfies(this.props.factorioVersion, release.info_json.factorio_version + ".x")) {
|
||||||
|
if(!newestRelease) {
|
||||||
|
newestRelease = release;
|
||||||
|
} else if(SemVer.gt(release.version, newestRelease.version)) {
|
||||||
|
newestRelease = release;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(newestRelease && newestRelease.version != this.props.mod.version) {
|
||||||
if(this.props.updateCountAdd)
|
if(this.props.updateCountAdd)
|
||||||
this.props.updateCountAdd();
|
this.props.updateCountAdd();
|
||||||
|
|
||||||
@ -43,7 +56,8 @@ class Mod extends React.Component {
|
|||||||
newVersionAvailable: true,
|
newVersionAvailable: true,
|
||||||
newVersion: {
|
newVersion: {
|
||||||
downloadUrl: newestRelease.download_url,
|
downloadUrl: newestRelease.download_url,
|
||||||
file_name: newestRelease.file_name
|
file_name: newestRelease.file_name,
|
||||||
|
version: newestRelease.version
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -83,6 +97,13 @@ class Mod extends React.Component {
|
|||||||
|
|
||||||
let version;
|
let version;
|
||||||
if(this.state.newVersionAvailable) {
|
if(this.state.newVersionAvailable) {
|
||||||
|
let faArrow;
|
||||||
|
if(SemVer.gt(this.state.newVersion.version, this.props.mod.version)) {
|
||||||
|
faArrow = "fa fa-arrow-circle-up";
|
||||||
|
} else {
|
||||||
|
faArrow = "fa fa-arrow-circle-down";
|
||||||
|
}
|
||||||
|
|
||||||
version = <span>{this.props.mod.version}
|
version = <span>{this.props.mod.version}
|
||||||
<a className="btn btn-xs btn-default update-button"
|
<a className="btn btn-xs btn-default update-button"
|
||||||
style={{
|
style={{
|
||||||
@ -104,7 +125,7 @@ class Mod extends React.Component {
|
|||||||
this.state.updateInProgress ?
|
this.state.updateInProgress ?
|
||||||
<div className='loader' style={{width: 15, height: 15, marginRight: 0, borderWidth: 3,}}></div>
|
<div className='loader' style={{width: 15, height: 15, marginRight: 0, borderWidth: 3,}}></div>
|
||||||
:
|
:
|
||||||
<i className="fa fa-arrow-circle-up" title="Update Mod" style={{fontSize: "15pt"}}></i>
|
<i className={faArrow} title="Update Mod" style={{fontSize: "15pt"}}></i>
|
||||||
}
|
}
|
||||||
</a>
|
</a>
|
||||||
</span>;
|
</span>;
|
||||||
@ -112,6 +133,16 @@ class Mod extends React.Component {
|
|||||||
version = this.props.mod.version;
|
version = this.props.mod.version;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let factorioVersion;
|
||||||
|
if(!this.props.mod.compatibility) {
|
||||||
|
factorioVersion = <span style={{color: "red"}}>
|
||||||
|
{this.props.mod.factorio_version}
|
||||||
|
<sup>not compatible</sup>
|
||||||
|
</span>
|
||||||
|
} else {
|
||||||
|
factorioVersion = this.props.mod.factorio_version;
|
||||||
|
}
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<tr data-mod-name={this.props.mod.name}
|
<tr data-mod-name={this.props.mod.name}
|
||||||
data-file-name={this.props.mod.file_name}
|
data-file-name={this.props.mod.file_name}
|
||||||
@ -120,7 +151,7 @@ class Mod extends React.Component {
|
|||||||
<td>{this.props.mod.title}</td>
|
<td>{this.props.mod.title}</td>
|
||||||
<td>{modStatus}</td>
|
<td>{modStatus}</td>
|
||||||
<td>{version}</td>
|
<td>{version}</td>
|
||||||
<td>{this.props.mod.factorio_version}</td>
|
<td>{factorioVersion}</td>
|
||||||
<td>
|
<td>
|
||||||
<input className='btn btn-default btn-sm'
|
<input className='btn btn-default btn-sm'
|
||||||
ref='modName'
|
ref='modName'
|
||||||
@ -150,6 +181,7 @@ Mod.propTypes = {
|
|||||||
deleteMod: React.PropTypes.func.isRequired,
|
deleteMod: React.PropTypes.func.isRequired,
|
||||||
updateMod: React.PropTypes.func.isRequired,
|
updateMod: React.PropTypes.func.isRequired,
|
||||||
updateCountAdd: React.PropTypes.func,
|
updateCountAdd: React.PropTypes.func,
|
||||||
|
factorioVersion: React.PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Mod
|
export default Mod
|
||||||
|
@ -446,6 +446,7 @@ class ModPackOverview extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
<div className="box-body">
|
<div className="box-body">
|
||||||
<ModManager
|
<ModManager
|
||||||
|
{...this.props}
|
||||||
installedMods={modpack.mods.mods}
|
installedMods={modpack.mods.mods}
|
||||||
deleteMod={this.modPackDeleteModHandler}
|
deleteMod={this.modPackDeleteModHandler}
|
||||||
toggleMod={this.modPackToggleModHandler}
|
toggleMod={this.modPackToggleModHandler}
|
||||||
|
@ -3,6 +3,7 @@ import ReactDOMServer from 'react-dom/server';
|
|||||||
import {IndexLink} from 'react-router';
|
import {IndexLink} from 'react-router';
|
||||||
import ModOverview from './Mods/ModOverview.jsx';
|
import ModOverview from './Mods/ModOverview.jsx';
|
||||||
import locks from "locks";
|
import locks from "locks";
|
||||||
|
import SemVer from 'semver';
|
||||||
|
|
||||||
class ModsContent extends React.Component {
|
class ModsContent extends React.Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
@ -24,6 +25,7 @@ class ModsContent extends React.Component {
|
|||||||
this.updateCountSubtract = this.updateCountSubtract.bind(this);
|
this.updateCountSubtract = this.updateCountSubtract.bind(this);
|
||||||
this.updateCountAdd = this.updateCountAdd.bind(this);
|
this.updateCountAdd = this.updateCountAdd.bind(this);
|
||||||
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
loggedIn: false,
|
loggedIn: false,
|
||||||
installedMods: null,
|
installedMods: null,
|
||||||
@ -178,19 +180,31 @@ class ModsContent extends React.Component {
|
|||||||
|
|
||||||
let correctData = JSON.parse(data.data);
|
let correctData = JSON.parse(data.data);
|
||||||
|
|
||||||
let checkboxes = []
|
let checkboxes = [];
|
||||||
|
let compatibleReleaseFound = false;
|
||||||
|
|
||||||
correctData.releases.reverse();
|
correctData.releases.reverse();
|
||||||
correctData.releases.forEach((release, index) => {
|
correctData.releases.forEach((release) => {
|
||||||
|
let incompatibleClass = "";
|
||||||
|
let isChecked = false;
|
||||||
|
|
||||||
|
if(!SemVer.satisfies(this.props.factorioVersion, release.info_json.factorio_version + ".x")) {
|
||||||
|
incompatibleClass = "incompatible";
|
||||||
|
} else if(compatibleReleaseFound == false) {
|
||||||
|
compatibleReleaseFound = true;
|
||||||
|
isChecked = true;
|
||||||
|
}
|
||||||
|
|
||||||
let date = new Date(release.released_at);
|
let date = new Date(release.released_at);
|
||||||
|
|
||||||
let singleBox = <tr>
|
let singleBox = <tr className={incompatibleClass}>
|
||||||
<td>
|
<td>
|
||||||
<input type="radio"
|
<input type="radio"
|
||||||
name="version"
|
name="version"
|
||||||
data-link={release.download_url}
|
data-link={release.download_url}
|
||||||
data-filename={release.file_name}
|
data-filename={release.file_name}
|
||||||
data-modid={modId}
|
data-modid={modId}
|
||||||
checked={index == 0 ? true : false}
|
checked={isChecked}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
@ -483,7 +497,6 @@ class ModsContent extends React.Component {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
let updateButtons = $('#manage-mods').find(".update-button");
|
let updateButtons = $('#manage-mods').find(".update-button");
|
||||||
// $('.update-button').click();
|
|
||||||
$.each(updateButtons, (k, v) => {
|
$.each(updateButtons, (k, v) => {
|
||||||
v.click();
|
v.click();
|
||||||
});
|
});
|
||||||
@ -524,6 +537,7 @@ class ModsContent extends React.Component {
|
|||||||
<section className="content">
|
<section className="content">
|
||||||
<ModOverview
|
<ModOverview
|
||||||
{...this.state}
|
{...this.state}
|
||||||
|
{...this.props}
|
||||||
loadDownloadList={this.loadDownloadList}
|
loadDownloadList={this.loadDownloadList}
|
||||||
submitFactorioLogin={this.handlerFactorioLogin}
|
submitFactorioLogin={this.handlerFactorioLogin}
|
||||||
toggleMod={this.toggleModHandler}
|
toggleMod={this.toggleModHandler}
|
||||||
@ -542,4 +556,8 @@ class ModsContent extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModsContent.propTypes = {
|
||||||
|
factorioVersion: React.PropTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
export default ModsContent;
|
export default ModsContent;
|
@ -21,7 +21,8 @@
|
|||||||
"react-dom": "^15.0.1",
|
"react-dom": "^15.0.1",
|
||||||
"react-native-listener": "^1.0.2",
|
"react-native-listener": "^1.0.2",
|
||||||
"react-router": "^2.3.0",
|
"react-router": "^2.3.0",
|
||||||
"sweetalert": "^1.1.3"
|
"sweetalert": "^1.1.3",
|
||||||
|
"semver": "latest"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"css-loader": "^0.23.1",
|
"css-loader": "^0.23.1",
|
||||||
|
Reference in New Issue
Block a user