aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfusion32 <marcopuzziello@gmail.com>2025-10-18 20:37:00 -0300
committerfusion32 <marcopuzziello@gmail.com>2025-10-18 20:39:12 -0300
commit48375acd7d6581b42b354618ed694a9d1cd25439 (patch)
treebd4fa70e4d39b3d637b218bbe7f52b86a96a1522
parentcd93a7c2bf927fd747fc188bdda98ea03b1f5e72 (diff)
downloadweb-48375acd7d6581b42b354618ed694a9d1cd25439.tar.gz
web-48375acd7d6581b42b354618ed694a9d1cd25439.zip
overall improvements + keep up with querymanager v0.2
-rw-r--r--.gitignore1
-rw-r--r--common.go67
-rw-r--r--config.cfg.dist (renamed from config.cfg)0
-rw-r--r--main.go2
-rw-r--r--query.go16
-rw-r--r--templates.go8
-rw-r--r--templates/character_create.tmpl2
-rw-r--r--templates/character_profile.tmpl2
-rw-r--r--templates/world_info.tmpl17
-rw-r--r--templates/world_list.tmpl6
10 files changed, 104 insertions, 17 deletions
diff --git a/.gitignore b/.gitignore
index d680a30..353c4bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,4 @@ bin
build
local
*.log
+config.cfg
diff --git a/common.go b/common.go
index 0676487..0430dcf 100644
--- a/common.go
+++ b/common.go
@@ -9,6 +9,7 @@ import (
"strings"
"time"
"unicode"
+ "unicode/utf8"
)
// TReadBuffer
@@ -83,7 +84,11 @@ func (ReadBuffer *TReadBuffer) ReadString() string {
Result := ""
if ReadBuffer.CanRead(Length) {
- Result = string(ReadBuffer.Buffer[ReadBuffer.Position:][:Length])
+ // IMPORTANT(fusion): The game server uses LATIN1 encoding, which forces
+ // the query manager to use LATIN1 encoding for text, at least on the
+ // protocol level.
+ Input := ReadBuffer.Buffer[ReadBuffer.Position:][:Length]
+ Result = string(Latin1ToUTF8(Input))
}
ReadBuffer.Position += Length
return Result
@@ -157,7 +162,11 @@ func (WriteBuffer *TWriteBuffer) Write32BE(Value uint32) {
}
func (WriteBuffer *TWriteBuffer) WriteString(String string) {
- Length := len(String)
+ // IMPORTANT(fusion): The game server uses LATIN1 encoding, which forces
+ // the query manager to use LATIN1 encoding for text, at least on the
+ // protocol level.
+ Output := UTF8ToLatin1([]byte(String))
+ Length := len(Output)
if Length < 0xFFFF {
WriteBuffer.Write16(uint16(Length))
} else {
@@ -166,7 +175,7 @@ func (WriteBuffer *TWriteBuffer) WriteString(String string) {
}
if WriteBuffer.CanWrite(Length) {
- copy(WriteBuffer.Buffer[WriteBuffer.Position:], String)
+ copy(WriteBuffer.Buffer[WriteBuffer.Position:], Output)
}
WriteBuffer.Position += Length
}
@@ -370,7 +379,7 @@ func WorldTypeString(Type int) string {
}
}
-func TimestampString(Timestamp int) string {
+func FormatTimestamp(Timestamp int) string {
String := "Never"
if Timestamp > 0 {
Time := time.Unix(int64(Timestamp), 0)
@@ -378,3 +387,53 @@ func TimestampString(Timestamp int) string {
}
return String
}
+
+func FormatDurationSince(Timestamp int) string {
+ String := "N/A"
+ if Timestamp > 0{
+ Duration := time.Since(time.Unix(int64(Timestamp), 0))
+ String = Duration.Truncate(time.Second).String()
+ }
+ return String
+}
+
+func UTF8FindNextLeadingByte(Buffer []byte) int {
+ Offset := 0
+ for Offset < len(Buffer) {
+ // NOTE(fusion): Allow the first byte to be a leading byte, in case we
+ // just want to advance from one leading byte to another.
+ if(Offset > 0 && utf8.RuneStart(Buffer[Offset])){
+ break
+ }
+ Offset += 1
+ }
+ return Offset
+}
+
+func UTF8ToLatin1(Buffer []byte) []byte {
+ ReadPos := 0
+ Result := []byte{}
+ for ReadPos < len(Buffer) {
+ Codepoint, Size := utf8.DecodeRune(Buffer[ReadPos:])
+ if Codepoint != utf8.RuneError {
+ ReadPos += Size
+ }else{
+ ReadPos += UTF8FindNextLeadingByte(Buffer[ReadPos:])
+ }
+
+ if Codepoint >= 0 && Codepoint <= 0xFF {
+ Result = append(Result, byte(Codepoint))
+ }else{
+ Result = append(Result, '?')
+ }
+ }
+ return Result
+}
+
+func Latin1ToUTF8(Buffer []byte) []byte {
+ Result := []byte{}
+ for ReadPos := range Buffer {
+ Result = utf8.AppendRune(Result, rune(Buffer[ReadPos]))
+ }
+ return Result
+}
diff --git a/config.cfg b/config.cfg.dist
index 81fd054..81fd054 100644
--- a/config.cfg
+++ b/config.cfg.dist
diff --git a/main.go b/main.go
index 679096f..e2d16ad 100644
--- a/main.go
+++ b/main.go
@@ -563,7 +563,7 @@ func HandleWorld(Context *THttpRequestContext) {
}
func main() {
- g_Log.Print("Tibia Web Server v0.1")
+ g_Log.Print("Tibia Web Server v0.2")
if !ReadConfig("config.cfg", WebKVCallback) {
return
}
diff --git a/query.go b/query.go
index 907e77f..3abca9a 100644
--- a/query.go
+++ b/query.go
@@ -45,8 +45,10 @@ type (
Type string
NumPlayers int
MaxPlayers int
- OnlineRecord int
- OnlineRecordTime string
+ OnlinePeak int
+ OnlinePeakTimestamp int
+ LastStartup int
+ LastShutdown int
}
TAccountSummary struct {
@@ -77,7 +79,7 @@ type (
Level int
Profession string
Residence string
- LastLogin string
+ LastLogin int
PremiumDays int
Online bool
Deleted bool
@@ -389,7 +391,7 @@ func (Connection *TQueryManagerConnection) GetCharacterProfile(CharacterName str
Character.Level = int(ReadBuffer.Read16())
Character.Profession = ReadBuffer.ReadString()
Character.Residence = ReadBuffer.ReadString()
- Character.LastLogin = TimestampString(int(ReadBuffer.Read32()))
+ Character.LastLogin = int(ReadBuffer.Read32())
Character.PremiumDays = int(ReadBuffer.Read16())
Character.Online = ReadBuffer.ReadFlag()
Character.Deleted = ReadBuffer.ReadFlag()
@@ -422,8 +424,10 @@ func (Connection *TQueryManagerConnection) GetWorlds() (Result int, Worlds []TWo
Worlds[Index].Type = WorldTypeString(int(ReadBuffer.Read8()))
Worlds[Index].NumPlayers = int(ReadBuffer.Read16())
Worlds[Index].MaxPlayers = int(ReadBuffer.Read16())
- Worlds[Index].OnlineRecord = int(ReadBuffer.Read16())
- Worlds[Index].OnlineRecordTime = TimestampString(int(ReadBuffer.Read32()))
+ Worlds[Index].OnlinePeak = int(ReadBuffer.Read16())
+ Worlds[Index].OnlinePeakTimestamp = int(ReadBuffer.Read32())
+ Worlds[Index].LastStartup = int(ReadBuffer.Read32())
+ Worlds[Index].LastShutdown = int(ReadBuffer.Read32())
}
}
default:
diff --git a/templates.go b/templates.go
index 1f47782..5281c14 100644
--- a/templates.go
+++ b/templates.go
@@ -58,7 +58,13 @@ var (
func InitTemplates() bool {
var Err error
- g_Templates, Err = template.ParseGlob("templates/*.tmpl")
+
+ CustomFuncs := template.FuncMap{
+ "FormatTimestamp": FormatTimestamp,
+ "FormatDurationSince": FormatDurationSince,
+ }
+
+ g_Templates, Err = template.New("").Funcs(CustomFuncs).ParseGlob("templates/*.tmpl")
if Err != nil {
g_LogErr.Printf("Failed to parse templates: %v", Err)
return false
diff --git a/templates/character_create.tmpl b/templates/character_create.tmpl
index c243f2d..1a235dd 100644
--- a/templates/character_create.tmpl
+++ b/templates/character_create.tmpl
@@ -1,6 +1,6 @@
{{template "_header.tmpl" .Common}}
<form class="box" action="/character/create" method="POST">
- <h1>Create Account</h1>
+ <h1>Create Character</h1>
<label for="character_name">NAME</label>
<input id="character_name" type="text" name="name"/>
diff --git a/templates/character_profile.tmpl b/templates/character_profile.tmpl
index 824e908..2711e03 100644
--- a/templates/character_profile.tmpl
+++ b/templates/character_profile.tmpl
@@ -35,7 +35,7 @@
</tr>
<tr>
<th>Last Login:</th>
- <td>{{.LastLogin}}</td>
+ <td>{{FormatTimestamp .LastLogin}}</td>
</tr>
<tr>
<th>Account Status:</th>
diff --git a/templates/world_info.tmpl b/templates/world_info.tmpl
index 578a0f7..353b674 100644
--- a/templates/world_info.tmpl
+++ b/templates/world_info.tmpl
@@ -16,13 +16,24 @@
<td>{{.NumPlayers}}</td>
</tr>
<tr>
- <th>Online Record:</th>
- {{if .OnlineRecord}}
- <td>{{.OnlineRecord}} players (on {{.OnlineRecordTime}})</td>
+ <th>Online Peak:</th>
+ {{if eq .OnlinePeak 1}}
+ <td>{{.OnlinePeak}} player (on {{FormatTimestamp .OnlinePeakTimestamp}})</td>
+ {{else if gt .OnlinePeak 1}}
+ <td>{{.OnlinePeak}} players (on {{FormatTimestamp .OnlinePeakTimestamp}})</td>
{{else}}
<td>None</td>
{{end}}
</tr>
+ <tr>
+ {{if gt .LastStartup .LastShutdown}}
+ <th>Uptime:</th>
+ <td>{{FormatDurationSince .LastStartup}}</td>
+ {{else}}
+ <th>Downtime:</th>
+ <td style="color: #A11;">{{FormatDurationSince .LastShutdown}}</td>
+ {{end}}
+ </tr>
</table>
<a class="button" href="/killstatistics?world={{.Name}}">Kill Statistics</a>
{{else}}
diff --git a/templates/world_list.tmpl b/templates/world_list.tmpl
index de9786c..07494b6 100644
--- a/templates/world_list.tmpl
+++ b/templates/world_list.tmpl
@@ -7,12 +7,18 @@
<th>Name</th>
<th>Type</th>
<th>Players Online</th>
+ <th>Status</th>
</tr>
{{range .Worlds}}
<tr>
<td><a href="/world?name={{.Name}}">{{.Name}}</a></td>
<td>{{.Type}}</td>
<td>{{.NumPlayers}}</td>
+ {{if gt .LastStartup .LastShutdown}}
+ <td style="color: #1A1;">Online</td>
+ {{else}}
+ <td style="color: #A11;">Offline</td>
+ {{end}}
</tr>
{{end}}
</table>