mirror of
https://github.com/Mezeporta/Erupe.git
synced 2025-12-12 23:14:36 +01:00
Add multi-region launcher support
Add custom launcher as well as support for both the original TW and JP launchers.
This commit is contained in:
62
README.md
62
README.md
@@ -1,31 +1,65 @@
|
||||
# Erupe
|
||||
## WARNING
|
||||
This project is in it's infancy and currently doesn't do anything worth noting. Additionally, it has no documentation, no support, and cannot be used without binary resources that are not in the repo.
|
||||
This project is in its infancy and currently doesn't do anything worth noting. Additionally, it has no documentation, no support, and cannot be used without binary resources that are not in the repo.
|
||||
|
||||
# General info
|
||||
Based on the TW version. Requires a local mirror of the original launcher site to be placed in `./www/g6_launcher` until I can RE the launcher and figure out which JS callbacks it requires.
|
||||
Originally based on the TW version, but (slowly) transitioning to JP.
|
||||
|
||||
## Installation
|
||||
Clone the repo
|
||||
Install PostgreSQL, launch psql shell, `CREATE DATABASE erupe;`.
|
||||
# Installation
|
||||
1. Clone the repo with `git clone https://github.com/Andoryuuta/Erupe.git`
|
||||
2. Install PostgreSQL
|
||||
3. Launch psql shell, `CREATE DATABASE erupe;`.
|
||||
|
||||
Setup db with golang-migrate:
|
||||
`go get -tags 'postgres' -u github.com/golang-migrate/migrate/cmd/migrate`
|
||||
`set POSTGRESQL_URL=postgres://postgres:password@localhost:5432/erupe?sslmode=disable`
|
||||
`migrate -database %POSTGRESQL_URL% -path migrations up`
|
||||
4. Setup database with golang-migrate:
|
||||
```
|
||||
> go get -tags 'postgres' -u github.com/golang-migrate/migrate/cmd/migrate
|
||||
|
||||
Open psql shell and manually insert an account into the users table.
|
||||
> set POSTGRESQL_URL=postgres://postgres:password@localhost:5432/erupe?sslmode=disable
|
||||
|
||||
Run `test.py` with python 3 to generate an entrance server response binary because the code isn't ported to Go yet.
|
||||
> migrate -database %POSTGRESQL_URL% -path migrations up
|
||||
```
|
||||
|
||||
Place a copy of the original TW launcher html/js/css in `./www/g6_launcher/`, and a copy of the serverlist at `./www/server/serverlist.xml`.
|
||||
5. Open psql shell and manually insert an account into the users table.
|
||||
|
||||
Manually extract the binary response from a pcap, strip the header, and decrypt the ~50 packets that are used in `./channelserver/session.go`, and place them in `./bin_resp/{OPCODE}_resp.bin`.
|
||||
6. Run `test.py` with python 3 to generate an entrance server response binary because the code isn't ported to Go yet. (**This requires a binary response that is not included in the repo**)
|
||||
|
||||
7. Manually extract the binary response from a pcap, strip the header, and decrypt the ~50 packets that are used in `./channelserver/session.go`, and place them in `./bin_resp/{OPCODE}_resp.bin`. (**These are not included in the repo**)
|
||||
|
||||
|
||||
# Use
|
||||
|
||||
|
||||
## Launcher
|
||||
Erupe now ships with a rudimentary custom launcher, so you don't need to obtain the original TW/JP files to simply get ingame. However, it does still support using the original files if you choose to. To set this up, place a copy of the original launcher html/js/css in `./www/tw/`, and `/www/jp/` for the TW and JP files respectively.
|
||||
|
||||
Then, modify the the `/launcher/js/launcher.js` file as such:
|
||||
* Find the call to `startUpdateProcess();` in a case statement and replace it with `finishUpdateProcess();`. (This disables the file check and updating)
|
||||
* (JP ONLY): replace all uses of "https://" with "http://" in the file.
|
||||
|
||||
Finally, edit `main.go` and change:
|
||||
|
||||
`go serveLauncherHTML(":80", false)`
|
||||
|
||||
to:
|
||||
|
||||
`go serveLauncherHTML(":80", true)`
|
||||
|
||||
# Usage
|
||||
### Note: If you are switching to/from the custom launcher html, you will have to clear your IE cache @ `C:\Users\<user>\AppData\Local\Microsoft\Windows\INetCache`.
|
||||
|
||||
## Server
|
||||
```
|
||||
cd Erupe
|
||||
go run .
|
||||
```
|
||||
|
||||
## Client
|
||||
Add to hosts:
|
||||
```
|
||||
127.0.0.1 mhfg.capcom.com.tw
|
||||
127.0.0.1 mhf-n.capcom.com.tw
|
||||
127.0.0.1 cog-members.mhf-z.jp
|
||||
127.0.0.1 www.capcom-onlinegames.jp
|
||||
127.0.0.1 srv-mhf.capcom-networks.jp
|
||||
```
|
||||
|
||||
Run mhf.exe normally (with locale emulator or appropriate timezone).
|
||||
|
||||
1
go.mod
1
go.mod
@@ -8,6 +8,7 @@ require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/golang-migrate/migrate v3.5.4+incompatible // indirect
|
||||
github.com/gorilla/handlers v1.4.2
|
||||
github.com/gorilla/mux v1.7.3
|
||||
github.com/julienschmidt/httprouter v1.3.0
|
||||
github.com/lib/pq v1.3.0
|
||||
)
|
||||
|
||||
2
go.sum
2
go.sum
@@ -9,6 +9,8 @@ github.com/golang-migrate/migrate v3.5.4+incompatible h1:R7OzwvCJTCgwapPCiX6DyBi
|
||||
github.com/golang-migrate/migrate v3.5.4+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk=
|
||||
github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg=
|
||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/lib/pq v1.3.0 h1:/qkRGz8zljWiDcFvgpwUpwIAPu3r07TDvs3Rws+o/pU=
|
||||
|
||||
@@ -2,40 +2,116 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"html"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"os"
|
||||
|
||||
"github.com/gorilla/handlers"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/gorilla/mux"
|
||||
//"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
func g6Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
http.ServeFile(w, r, "www/g6_launcher/index.html")
|
||||
// GetOutboundIP4 gets the preferred outbound ip4 of this machine
|
||||
// From https://stackoverflow.com/a/37382208
|
||||
func GetOutboundIP4() net.IP {
|
||||
conn, err := net.Dial("udp4", "8.8.8.8:80")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
localAddr := conn.LocalAddr().(*net.UDPAddr)
|
||||
|
||||
return localAddr.IP.To4()
|
||||
}
|
||||
|
||||
func serverList(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO(Andoryuuta): Redo launcher server to allow configurable serverlist host and port.
|
||||
fmt.Fprintf(w, `<?xml version="1.0"?><server_groups><group idx='0' nam='Erupe' ip='%s' port="53312"/></server_groups>`, GetOutboundIP4().String())
|
||||
|
||||
}
|
||||
|
||||
func serverUniqueName(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
|
||||
dump, err := httputil.DumpRequest(r, true)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprint(err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
fmt.Println(string(dump))
|
||||
|
||||
func serverUniqueName(w http.ResponseWriter, r *http.Request) {
|
||||
// TODO(Andoryuuta): Implement checking for unique character name.
|
||||
fmt.Fprintf(w, `<?xml version="1.0" encoding="ISO-8859-1"?><uniq code="200">OK</uniq>`)
|
||||
}
|
||||
|
||||
// serveLauncherHTML is responsible for serving the launcher HTML and (HACK) serverlist.xml.
|
||||
func serveLauncherHTML(listenAddr string) {
|
||||
// Manually route the folder root to index.html? Is there a better way to do this?
|
||||
router := httprouter.New()
|
||||
router.GET("/g6_launcher/", g6Index)
|
||||
router.GET("/server/unique.php", serverUniqueName)
|
||||
func jpLogin(w http.ResponseWriter, r *http.Request) {
|
||||
// HACK: Return the given password back as the `skey` to defer the login logic to the sign server.
|
||||
|
||||
static := httprouter.New()
|
||||
static.ServeFiles("/*filepath", http.Dir("www"))
|
||||
router.NotFound = static
|
||||
resultJSON := fmt.Sprintf(`{"result": "Ok", "skey": "%s", "code": "000", "msg": ""}`, r.FormValue("pw"))
|
||||
|
||||
fmt.Fprintf(w,
|
||||
`<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html>
|
||||
<body onload="doPost();">
|
||||
<script type="text/javascript">
|
||||
function doPost(){
|
||||
parent.postMessage(document.getElementById("result").getAttribute("value"), "http://cog-members.mhf-z.jp");
|
||||
}
|
||||
</script>
|
||||
<input id="result" value="%s"/>
|
||||
</body>
|
||||
</html>`, html.EscapeString(resultJSON))
|
||||
|
||||
http.ListenAndServe(listenAddr, handlers.LoggingHandler(os.Stdout, router))
|
||||
}
|
||||
|
||||
func setupServerlistRoutes(r *mux.Router) {
|
||||
// TW
|
||||
twServerList := r.Host("mhf-n.capcom.com.tw").Subrouter()
|
||||
twServerList.HandleFunc("/server/unique.php", serverUniqueName) // Name checking is also done on this host.
|
||||
twServerList.HandleFunc("/server/serverlist.xml", serverList)
|
||||
|
||||
// JP
|
||||
jpServerList := r.Host("srv-mhf.capcom-networks.jp").Subrouter()
|
||||
jpServerList.HandleFunc("/serverlist.xml", serverList)
|
||||
}
|
||||
|
||||
func setupOriginalLauncherRotues(r *mux.Router) {
|
||||
// TW
|
||||
twMain := r.Host("mhfg.capcom.com.tw").Subrouter()
|
||||
twMain.PathPrefix("/").Handler(http.FileServer(http.Dir("./www/tw/")))
|
||||
|
||||
// JP
|
||||
jpMain := r.Host("cog-members.mhf-z.jp").Subrouter()
|
||||
jpMain.PathPrefix("/").Handler(http.FileServer(http.Dir("./www/jp/")))
|
||||
|
||||
// JP Launcher does additional auth over HTTP that the TW launcher doesn't.
|
||||
jpAuth := r.Host("www.capcom-onlinegames.jp").Subrouter()
|
||||
jpAuth.HandleFunc("/auth/launcher/login", jpLogin) //.Methods("POST")
|
||||
jpAuth.PathPrefix("/auth/").Handler(http.StripPrefix("/auth/", http.FileServer(http.Dir("./www/jp/auth/"))))
|
||||
|
||||
}
|
||||
|
||||
func setupCustomLauncherRotues(r *mux.Router) {
|
||||
// TW
|
||||
twMain := r.Host("mhfg.capcom.com.tw").Subrouter()
|
||||
twMain.PathPrefix("/g6_launcher/").Handler(http.StripPrefix("/g6_launcher/", http.FileServer(http.Dir("./www/erupe/"))))
|
||||
|
||||
// JP
|
||||
jpMain := r.Host("cog-members.mhf-z.jp").Subrouter()
|
||||
jpMain.PathPrefix("/launcher/").Handler(http.StripPrefix("/launcher/", http.FileServer(http.Dir("./www/erupe"))))
|
||||
}
|
||||
|
||||
// serveLauncherHTML is responsible for serving the launcher HTML, serverlist, unique name check, and JP auth.
|
||||
func serveLauncherHTML(listenAddr string, useOriginalLauncher bool) {
|
||||
r := mux.NewRouter()
|
||||
|
||||
setupServerlistRoutes(r)
|
||||
|
||||
if useOriginalLauncher {
|
||||
setupOriginalLauncherRotues(r)
|
||||
} else {
|
||||
setupCustomLauncherRotues(r)
|
||||
}
|
||||
/*
|
||||
http.ListenAndServe(listenAddr, handlers.CustomLoggingHandler(os.Stdout, r, func(writer io.Writer, params handlers.LogFormatterParams) {
|
||||
dump, _ := httputil.DumpRequest(params.Request, true)
|
||||
writer.Write(dump)
|
||||
}))
|
||||
*/
|
||||
|
||||
http.ListenAndServe(listenAddr, handlers.LoggingHandler(os.Stdout, r))
|
||||
}
|
||||
|
||||
2
main.go
2
main.go
@@ -30,7 +30,7 @@ func main() {
|
||||
}
|
||||
|
||||
// Finally start our server(s).
|
||||
go serveLauncherHTML(":80")
|
||||
go serveLauncherHTML(":80", false)
|
||||
go doEntranceServer(":53310")
|
||||
|
||||
signServer := signserver.NewServer(
|
||||
|
||||
@@ -47,6 +47,8 @@ func (session *Session) handlePacket(pkt []byte) error {
|
||||
bf := byteframe.NewByteFrameFromBytes(pkt)
|
||||
reqType := string(bf.ReadNullTerminatedBytes())
|
||||
switch reqType {
|
||||
case "DLTSKEYSIGN:100":
|
||||
fallthrough
|
||||
case "DSGN:100":
|
||||
session.handleDSGNRequest(bf)
|
||||
break
|
||||
|
||||
@@ -64,6 +64,8 @@ func (s *Server) acceptClients() {
|
||||
}
|
||||
|
||||
func (s *Server) handleConnection(sid int, conn net.Conn) {
|
||||
fmt.Println("Got connection to sign server")
|
||||
|
||||
// Client initalizes the connection with a one-time buffer of 8 NULL bytes.
|
||||
nullInit := make([]byte, 8)
|
||||
_, err := io.ReadFull(conn, nullInit)
|
||||
|
||||
75
www/erupe/charsel.html
Normal file
75
www/erupe/charsel.html
Normal file
@@ -0,0 +1,75 @@
|
||||
<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Simple MHF launcher</title>
|
||||
|
||||
<!--
|
||||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/firebug-lite/1.4.0/firebug-lite.js#startOpened,overrideConsole"></script>
|
||||
-->
|
||||
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.0/css/bootstrap.min.css">
|
||||
<!--[if IE 9]>
|
||||
<link href="css/bootstrap-ie9.css" rel="stylesheet">
|
||||
<![endif]-->
|
||||
<!--[if lt IE 9]>
|
||||
<link href="css/bootstrap-ie8.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/g/html5shiv@3.7.3"></script>
|
||||
<![endif]-->
|
||||
|
||||
<!--[if gte IE 9]><!-->
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.0/js/bootstrap.bundle.min.js"></script>
|
||||
<!--<![endif]-->
|
||||
<!--[if IE 9]>
|
||||
<script src="js/bootstrap-ie9.js"></script>
|
||||
<![endif]-->
|
||||
<!--[if lte IE 8]>
|
||||
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
|
||||
<script src="js/bootstrap-ie8.js"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.0/js/bootstrap.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
|
||||
<link rel="stylesheet" href="css/main.css">
|
||||
<script type="text/javascript" src="js/charsel.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="alertBox"></div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 text-center">
|
||||
<div style="height:5em; margin-top:3em;">
|
||||
<h2>
|
||||
Erupe Simple Launcher
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-2"></div>
|
||||
<div class="col-8 text-center">
|
||||
<h5 class="mb-3">Character Select</h5>
|
||||
<ul id="characterlist" class="list-group char-select-list">
|
||||
</ul>
|
||||
</div>
|
||||
<div class="col-2"></div>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12 text-center">
|
||||
<button id="selectButton" class="btn btn-primary">Select</button>
|
||||
<!--
|
||||
<button id="newButton" class="btn btn-primary">New</button>
|
||||
<button id="deleteButton" class="btn btn-primary">Delete</button>
|
||||
-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
13
www/erupe/css/main.css
Normal file
13
www/erupe/css/main.css
Normal file
@@ -0,0 +1,13 @@
|
||||
body {
|
||||
background-color: #f8f9fa;
|
||||
}
|
||||
|
||||
html,body {
|
||||
height: 100%;
|
||||
overflow:hidden;
|
||||
}
|
||||
|
||||
.char-select-list {
|
||||
height: 15em;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
57
www/erupe/index.html
Normal file
57
www/erupe/index.html
Normal file
@@ -0,0 +1,57 @@
|
||||
<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Simple MHF launcher</title>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.0/css/bootstrap.min.css">
|
||||
<!--[if IE 9]>
|
||||
<link href="css/bootstrap-ie9.css" rel="stylesheet">
|
||||
<![endif]-->
|
||||
<!--[if lt IE 9]>
|
||||
<link href="css/bootstrap-ie8.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/g/html5shiv@3.7.3"></script>
|
||||
<![endif]-->
|
||||
|
||||
<!--[if gte IE 9]><!-->
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.0/js/bootstrap.bundle.min.js"></script>
|
||||
<!--<![endif]-->
|
||||
<!--[if IE 9]>
|
||||
<script src="js/bootstrap-ie9.js"></script>
|
||||
<![endif]-->
|
||||
<!--[if lte IE 8]>
|
||||
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
|
||||
<script src="js/bootstrap-ie8.js"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.0/js/bootstrap.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
|
||||
<link rel="stylesheet" href="css/main.css">
|
||||
<script type="text/javascript" src="js/main.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav id="titlebar" class="navbar navbar-expand-lg navbar-dark bg-dark">
|
||||
<a class="navbar-brand" href="#">MHF <i>Erupe</i></a>
|
||||
<ul class="navbar-nav mr-auto"></ul>
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item">
|
||||
<a id="exit" class="nav-link" href="#">×</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
|
||||
<div id="alertBox"></div>
|
||||
|
||||
<div class="container-fluid px-0 h-100">
|
||||
<div class="row no-gutters h-100">
|
||||
<div class="col-12">
|
||||
<iframe src="login.html" style="width: 100%; height: 100%; border: none; overflow:hidden;" frameBorder="0" scrolling="no"></iframe>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
98
www/erupe/js/charsel.js
Normal file
98
www/erupe/js/charsel.js
Normal file
@@ -0,0 +1,98 @@
|
||||
function createErrorAlert(message) {
|
||||
parent.postMessage(message, "*");
|
||||
}
|
||||
|
||||
function createCharListItem(name, uid, weapon, HR, GR, lastLogin, sex) {
|
||||
var topDiv = $('<div/>')
|
||||
.attr("href", "#")
|
||||
.attr("uid", uid)
|
||||
.addClass("char-list-entry list-group-item list-group-item-action flex-column align-items-start");
|
||||
|
||||
var topLine = $('<div/>')
|
||||
.addClass("d-flex w-100 justify-content-between")
|
||||
.append(
|
||||
$('<h5/>')
|
||||
.addClass("mb-1")
|
||||
.text(name)
|
||||
)
|
||||
.append(
|
||||
$('<small/>')
|
||||
.text('ID:' + uid)
|
||||
);
|
||||
|
||||
var bottomLine = $('<div/>')
|
||||
.addClass("d-flex w-100 justify-content-between")
|
||||
.append($('<small/>').text('Weapon: ' + weapon))
|
||||
.append($('<small/>').text('HR: ' + HR))
|
||||
.append($('<small/>').text('GR: ' + GR))
|
||||
.append($('<small/>').text('LastLogin: ' + lastLogin))
|
||||
.append($('<small/>').text('Sex: ' + sex));
|
||||
|
||||
topDiv.append(topLine);
|
||||
topDiv.append(bottomLine);
|
||||
|
||||
$("#characterlist").append(topDiv);
|
||||
}
|
||||
|
||||
$(function() {
|
||||
try {
|
||||
var charInfo = window.external.getCharacterInfo();
|
||||
} catch (e) {
|
||||
createErrorAlert("Error on getCharacterInfo!");
|
||||
}
|
||||
|
||||
try{
|
||||
// JQuery's parseXML isn't working properly on IE11, use the activeX XMLDOM instead.
|
||||
//$xmlDoc = $.parseXML(charInfo),
|
||||
$xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
|
||||
$xmlDoc.async = "false";
|
||||
$xmlDoc.loadXML(charInfo);
|
||||
|
||||
$xml = $($xmlDoc);
|
||||
} catch (e) {
|
||||
createErrorAlert("Error parsing character info xml!" + e);
|
||||
}
|
||||
|
||||
// Go over each "Character" element in the XML and then create a new list item for it.
|
||||
try {
|
||||
$($xml).find("Character").each(function(){
|
||||
createCharListItem(
|
||||
$(this).attr('name'),
|
||||
$(this).attr('uid'),
|
||||
$(this).attr('weapon'),
|
||||
$(this).attr('HR'),
|
||||
$(this).attr('GR'),
|
||||
$(this).attr('lastLogin'),
|
||||
$(this).attr('sex')
|
||||
);
|
||||
});
|
||||
} catch (e) {
|
||||
createErrorAlert("Error searching character info xml!");
|
||||
}
|
||||
|
||||
// Set the active character selection on click.
|
||||
$(".char-list-entry").click(function(){
|
||||
if(!$(this).hasClass("active")) {
|
||||
$(".char-list-entry.active").removeClass("active");
|
||||
$(this).addClass("active");
|
||||
}
|
||||
});
|
||||
|
||||
$("#selectButton").on("click", function() {
|
||||
// Get the active character selection.
|
||||
var selectedUid = $(".char-list-entry.active").attr("uid");
|
||||
|
||||
// Call into the native launcher select function.
|
||||
try{
|
||||
window.external.selectCharacter(selectedUid, selectedUid)
|
||||
} catch(e) {
|
||||
createErrorAlert("Error on select character!");
|
||||
}
|
||||
|
||||
// If we didn't error before, just close the launcher to start the game.
|
||||
setTimeout(function(){
|
||||
window.external.exitLauncher();
|
||||
}, 500);
|
||||
});
|
||||
|
||||
});
|
||||
38
www/erupe/js/login.js
Normal file
38
www/erupe/js/login.js
Normal file
@@ -0,0 +1,38 @@
|
||||
function createErrorAlert(message) {
|
||||
parent.postMessage(message, "*");
|
||||
}
|
||||
|
||||
|
||||
// Function to continually check if we got a login result yet,
|
||||
// then navigating to the character selection if we did.
|
||||
function checkAuthResult() {
|
||||
var loginResult = window.external.getLastAuthResult();
|
||||
console.log('|' + loginResult + '|');
|
||||
if(loginResult == "AUTH_PROGRESS") {
|
||||
setTimeout(checkAuthResult, 1500);
|
||||
} else if (loginResult == "AUTH_SUCCESS") {
|
||||
window.location.href = 'charsel.html'
|
||||
} else {
|
||||
createErrorAlert("Error logging in!");
|
||||
}
|
||||
}
|
||||
|
||||
$(function() {
|
||||
|
||||
// Login form submission.
|
||||
$("#loginform").submit(function(e){
|
||||
e.preventDefault();
|
||||
|
||||
username = $("#username").val();
|
||||
password = $("#password").val();
|
||||
|
||||
try{
|
||||
window.external.loginCog(username, password, password);
|
||||
} catch(e){
|
||||
createErrorAlert("Error on loginCog: " + e);
|
||||
}
|
||||
|
||||
checkAuthResult();
|
||||
});
|
||||
|
||||
});
|
||||
93
www/erupe/js/main.js
Normal file
93
www/erupe/js/main.js
Normal file
@@ -0,0 +1,93 @@
|
||||
// Helper function to dynamically create a bootstrap alert box.
|
||||
function createErrorAlert(message) {
|
||||
var tmpDiv = $('<div/>')
|
||||
.attr("id", "myAlertBoxID")
|
||||
.attr("role", "alert")
|
||||
.addClass("alert alert-danger alert-dismissible fade show")
|
||||
|
||||
tmpDiv.append(message);
|
||||
tmpDiv.append($("<button/>")
|
||||
.attr("type", "button")
|
||||
.addClass("close")
|
||||
.attr("data-dismiss", "alert")
|
||||
.attr("aria-label", "Close")
|
||||
.append($("<span/>")
|
||||
.attr("aria-hidden", "true")
|
||||
.text("×")
|
||||
));
|
||||
|
||||
$("#alertBox").append(tmpDiv);
|
||||
}
|
||||
|
||||
function doLauncherInitalize() {
|
||||
try{
|
||||
window.external.getMhfMutexNumber();
|
||||
} catch(e){
|
||||
createErrorAlert("Error getting Mhf mutex number! " + e);
|
||||
}
|
||||
|
||||
try{
|
||||
var serverListXml = window.external.getServerListXml();
|
||||
} catch(e){
|
||||
createErrorAlert("Error getting serverlist.xml! " + e);
|
||||
}
|
||||
|
||||
if(serverListXml == ""){
|
||||
createErrorAlert("Got empty serverlist.xml!");
|
||||
}
|
||||
console.log(serverListXml);
|
||||
|
||||
try{
|
||||
var lastServerIndex = window.external.getIniLastServerIndex();
|
||||
} catch(e){
|
||||
createErrorAlert("Error on getIniLastServerIndex: " + e);
|
||||
}
|
||||
console.log("Last server index:" + lastServerIndex);
|
||||
|
||||
try{
|
||||
window.external.setIniLastServerIndex(0);
|
||||
} catch(e){
|
||||
createErrorAlert("Error on setIniLastServerIndex: " + e);
|
||||
}
|
||||
|
||||
try{
|
||||
var mhfBootMode = window.external.getMhfBootMode();
|
||||
} catch(e){
|
||||
createErrorAlert("Error on getMhfBootMode: " + e);
|
||||
}
|
||||
console.log("mhfBootMode:" + mhfBootMode);
|
||||
|
||||
try{
|
||||
var userId = window.external.getUserId();
|
||||
} catch(e){
|
||||
createErrorAlert("Error on getUserId: " + e);
|
||||
}
|
||||
console.log("userId:" + userId);
|
||||
|
||||
try{
|
||||
var password = window.external.getPassword();
|
||||
} catch(e){
|
||||
createErrorAlert("Error on getPassword: " + e);
|
||||
}
|
||||
console.log("password:" + password);
|
||||
}
|
||||
|
||||
$(function() {
|
||||
// Setup the titlebar and exit button so that the window works how you would expect.
|
||||
$("#titlebar").on("click", function(e) {
|
||||
window.external.beginDrag(true);
|
||||
});
|
||||
|
||||
$("#exit").on("click", function(e) {
|
||||
window.external.closeWindow();
|
||||
});
|
||||
|
||||
// Setup the error message passthrough
|
||||
$(window).on("message onmessage", function(e) {
|
||||
var data = e.originalEvent.data;
|
||||
createErrorAlert(data)
|
||||
});
|
||||
|
||||
// Initialize the launcher by calling the native/external functions it exposes in the proper order.
|
||||
doLauncherInitalize();
|
||||
});
|
||||
68
www/erupe/login.html
Normal file
68
www/erupe/login.html
Normal file
@@ -0,0 +1,68 @@
|
||||
<!DOCTYPE HTML PUBLIC"-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Simple MHF launcher</title>
|
||||
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.0/css/bootstrap.min.css">
|
||||
<!--[if IE 9]>
|
||||
<link href="css/bootstrap-ie9.css" rel="stylesheet">
|
||||
<![endif]-->
|
||||
<!--[if lt IE 9]>
|
||||
<link href="css/bootstrap-ie8.css" rel="stylesheet">
|
||||
<script src="https://cdn.jsdelivr.net/g/html5shiv@3.7.3"></script>
|
||||
<![endif]-->
|
||||
|
||||
<!--[if gte IE 9]><!-->
|
||||
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.0/js/bootstrap.bundle.min.js"></script>
|
||||
<!--<![endif]-->
|
||||
<!--[if IE 9]>
|
||||
<script src="js/bootstrap-ie9.js"></script>
|
||||
<![endif]-->
|
||||
<!--[if lte IE 8]>
|
||||
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
|
||||
<script src="js/bootstrap-ie8.js"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.0/js/bootstrap.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
|
||||
<link rel="stylesheet" href="css/main.css">
|
||||
<script type="text/javascript" src="js/login.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="alertBox"></div>
|
||||
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 text-center">
|
||||
<div style="height:5em; margin-top:3em;">
|
||||
<h2>
|
||||
Erupe Simple Launcher
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-4"></div>
|
||||
<div class="col-4 text-center">
|
||||
<div class="segment">
|
||||
<h5 class="mb-3">Login</h5>
|
||||
<form id="loginform">
|
||||
<div class="form-group">
|
||||
<input type="text" class="form-control" id="username" placeholder="Username">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="password" class="form-control" id="password" placeholder="Password">
|
||||
</div>
|
||||
<button id="submitButton" type="submit" class="btn btn-primary">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-4"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user