structures, properties

This commit is contained in:
Robert Janetzko 2022-05-05 10:55:33 +00:00
parent 765a7cef2b
commit 093f7dacf9
20 changed files with 199 additions and 45 deletions

View File

@ -27,7 +27,8 @@
// Add the IDs of extensions you want installed when the container is created. // Add the IDs of extensions you want installed when the container is created.
"extensions": [ "extensions": [
"golang.Go", "golang.Go",
"jinliming2.vscode-go-template" "jinliming2.vscode-go-template",
"golang.go"
], ],
// Use 'forwardPorts' to make a list of ports inside the container available locally. // Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [], // "forwardPorts": [],

View File

@ -8,7 +8,8 @@
"HistoricalEventDanceFormCreated.FormId": "danceForm", "HistoricalEventDanceFormCreated.FormId": "danceForm",
"HistoricalEventMusicalFormCreated.FormId": "musicalForm", "HistoricalEventMusicalFormCreated.FormId": "musicalForm",
"HistoricalEventPoeticFormCreated.FormId": "poeticForm", "HistoricalEventPoeticFormCreated.FormId": "poeticForm",
"HistoricalEventHfReachSummit.MountainPeakId": "mountain" "HistoricalEventHfReachSummit.MountainPeakId": "mountain",
"HistoricalEventBuildingProfileAcquired.StructureId": "structure"
}, },
"AdditionalFields": { "AdditionalFields": {
"DfWorld": [ "DfWorld": [
@ -45,6 +46,10 @@
{ {
"Name": "SiteId", "Name": "SiteId",
"Type": "int" "Type": "int"
},
{
"Name": "Ruin",
"Type": "bool"
} }
], ],
"HistoricalFigure": [ "HistoricalFigure": [
@ -81,6 +86,12 @@
"Type": "HistoricalEventRelationshipRelationship" "Type": "HistoricalEventRelationshipRelationship"
} }
], ],
"HistoricalEventBuildingProfileAcquired": [
{
"Name": "StructureId",
"Type": "int"
}
],
"HistoricalEventHfReachSummit": [ "HistoricalEventHfReachSummit": [
{ {
"Name": "MountainPeakId", "Name": "MountainPeakId",
@ -128,6 +139,12 @@
"Name": "OccasionEventcol", "Name": "OccasionEventcol",
"Type": "int" "Type": "int"
} }
],
"WorldConstruction": [
{
"Name": "Parts",
"Type": "[]int"
}
] ]
} }
} }

View File

@ -12,5 +12,5 @@ buildMacOs:
genisoimage -D -V "LegendsBrowser" -no-pad -r -apple -o /tmp/build/uncompressed.dmg /tmp/build/macos genisoimage -D -V "LegendsBrowser" -no-pad -r -apple -o /tmp/build/uncompressed.dmg /tmp/build/macos
dmg dmg /tmp/build/uncompressed.dmg ../bin/LegendsBrowser.dmg dmg dmg /tmp/build/uncompressed.dmg ../bin/LegendsBrowser.dmg
run: runLast:
cd backend && go run main.go go run main.go -c conf.json -l=true

5
backend/conf.json Normal file
View File

@ -0,0 +1,5 @@
{
"LastPath": "/workspaces/legendsbrowser/inputs",
"LastFile": "/workspaces/legendsbrowser/inputs/Stalkmatches-00254-08-26-legends.xml",
"DebugTemplates": true
}

View File

@ -20,7 +20,8 @@ var static embed.FS
func main() { func main() {
f := flag.String("f", "", "open a file") f := flag.String("f", "", "open a file")
p := flag.Bool("p", false, "start profiling") p := flag.Bool("p", false, "start profiling")
d := flag.Bool("d", false, "debug templates") c := flag.String("c", "", "config file")
l := flag.Bool("l", false, "open last file")
flag.Parse() flag.Parse()
if *p { if *p {
@ -30,10 +31,19 @@ func main() {
}() }()
} }
templates.DebugTemplates = *d config, err := server.LoadConfig(*c)
if err != nil {
log.Fatal(err)
}
templates.DebugTemplates = config.DebugTemplates
var world *model.DfWorld var world *model.DfWorld
if *l {
*f = config.LastFile
}
if len(*f) > 0 { if len(*f) > 0 {
w, err := model.Parse(*f, nil) w, err := model.Parse(*f, nil)
if err != nil { if err != nil {
@ -44,7 +54,7 @@ func main() {
world = w world = w
} }
err := server.StartServer(world, static) err = server.StartServer(config, world, static)
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
} }

View File

@ -115,7 +115,7 @@ func (c *Context) siteStructure(siteId, structureId int, prefix string) string {
func (c *Context) site(id int, prefix string) string { func (c *Context) site(id int, prefix string) string {
if x, ok := c.World.Sites[id]; ok { if x, ok := c.World.Sites[id]; ok {
return fmt.Sprintf(`%s <a class="site" href="/site/%d"><i class="%s fa-xs"></i> %s</a>`, prefix, x.Id(), x.Icon(), util.Title(x.Name())) return fmt.Sprintf(`%s <a class="site%s" href="/site/%d"><i class="%s fa-xs"></i> %s</a>`, prefix, util.If(x.Ruin, " ruin", ""), x.Id(), x.Icon(), util.Title(x.Name()))
} }
return "UNKNOWN SITE" return "UNKNOWN SITE"
} }
@ -123,7 +123,7 @@ func (c *Context) site(id int, prefix string) string {
func (c *Context) structure(siteId, structureId int) string { func (c *Context) structure(siteId, structureId int) string {
if x, ok := c.World.Sites[siteId]; ok { if x, ok := c.World.Sites[siteId]; ok {
if y, ok := x.Structures[structureId]; ok { if y, ok := x.Structures[structureId]; ok {
return fmt.Sprintf(`<a class="structure" href="/site/%d/structure/%d"><i class="%s fa-xs"></i> %s</a>`, siteId, structureId, y.Icon(), util.Title(y.Name())) return fmt.Sprintf(`<a class="structure%s" href="/site/%d/structure/%d"><i class="%s fa-xs"></i> %s</a>`, util.If(y.Ruin, " ruin", ""), siteId, structureId, y.Icon(), util.Title(y.Name()))
} }
} }
return "UNKNOWN STRUCTURE" return "UNKNOWN STRUCTURE"

View File

@ -407,8 +407,17 @@ func (x *HistoricalEventBodyAbused) Html(c *Context) string {
} }
func (x *HistoricalEventBuildingProfileAcquired) Html(c *Context) string { func (x *HistoricalEventBuildingProfileAcquired) Html(c *Context) string {
return util.If(x.AcquirerEnid != -1, c.entity(x.AcquirerEnid), c.hf(x.AcquirerHfid)) + mode := " acquired "
util.If(x.PurchasedUnowned, " purchased ", " inherited ") + switch {
case x.PurchasedUnowned:
mode = " purchased "
case x.RebuiltRuined:
mode = " rebuilt "
case x.Inherited:
mode = " iinherited "
}
return util.If(x.AcquirerEnid != -1, c.entity(x.AcquirerEnid), c.hf(x.AcquirerHfid)) + mode +
c.property(x.SiteId, x.BuildingProfileId) + c.site(x.SiteId, " in") + c.property(x.SiteId, x.BuildingProfileId) + c.site(x.SiteId, " in") +
util.If(x.LastOwnerHfid != -1, " formerly owned by "+c.hfRelated(x.LastOwnerHfid, x.AcquirerHfid), "") util.If(x.LastOwnerHfid != -1, " formerly owned by "+c.hfRelated(x.LastOwnerHfid, x.AcquirerHfid), "")
} }

View File

@ -5253,6 +5253,7 @@ type HistoricalEventBuildingProfileAcquired struct {
PurchasedUnowned bool `json:"purchasedUnowned" legend:"base" related:""` // purchased_unowned PurchasedUnowned bool `json:"purchasedUnowned" legend:"base" related:""` // purchased_unowned
RebuiltRuined bool `json:"rebuiltRuined" legend:"base" related:""` // rebuilt_ruined RebuiltRuined bool `json:"rebuiltRuined" legend:"base" related:""` // rebuilt_ruined
SiteId int `json:"siteId" legend:"base" related:""` // site_id SiteId int `json:"siteId" legend:"base" related:""` // site_id
StructureId int `json:"structureId" legend:"add" related:"structure"` // StructureId
} }
func NewHistoricalEventBuildingProfileAcquired() *HistoricalEventBuildingProfileAcquired { func NewHistoricalEventBuildingProfileAcquired() *HistoricalEventBuildingProfileAcquired {
@ -5262,6 +5263,7 @@ func NewHistoricalEventBuildingProfileAcquired() *HistoricalEventBuildingProfile
BuildingProfileId: -1, BuildingProfileId: -1,
LastOwnerHfid: -1, LastOwnerHfid: -1,
SiteId: -1, SiteId: -1,
StructureId: -1,
} }
} }
func (x *HistoricalEventBuildingProfileAcquired) Type() string { return "building profile acquired" } func (x *HistoricalEventBuildingProfileAcquired) Type() string { return "building profile acquired" }
@ -5274,7 +5276,7 @@ func (x *HistoricalEventBuildingProfileAcquired) RelatedToHf(id int) bool {
func (x *HistoricalEventBuildingProfileAcquired) RelatedToArtifact(id int) bool { return false } func (x *HistoricalEventBuildingProfileAcquired) RelatedToArtifact(id int) bool { return false }
func (x *HistoricalEventBuildingProfileAcquired) RelatedToSite(id int) bool { return x.SiteId == id } func (x *HistoricalEventBuildingProfileAcquired) RelatedToSite(id int) bool { return x.SiteId == id }
func (x *HistoricalEventBuildingProfileAcquired) RelatedToStructure(siteId, id int) bool { func (x *HistoricalEventBuildingProfileAcquired) RelatedToStructure(siteId, id int) bool {
return false return x.RelatedToSite(siteId) && (x.StructureId == id)
} }
func (x *HistoricalEventBuildingProfileAcquired) RelatedToRegion(id int) bool { return false } func (x *HistoricalEventBuildingProfileAcquired) RelatedToRegion(id int) bool { return false }
func (x *HistoricalEventBuildingProfileAcquired) RelatedToWorldConstruction(id int) bool { func (x *HistoricalEventBuildingProfileAcquired) RelatedToWorldConstruction(id int) bool {
@ -5309,6 +5311,9 @@ func (x *HistoricalEventBuildingProfileAcquired) MarshalJSON() ([]byte, error) {
if x.SiteId != -1 { if x.SiteId != -1 {
d["siteId"] = x.SiteId d["siteId"] = x.SiteId
} }
if x.StructureId != -1 {
d["structureId"] = x.StructureId
}
return json.Marshal(d) return json.Marshal(d)
} }
@ -21447,6 +21452,7 @@ type Structure struct {
Subtype StructureSubtype `json:"subtype" legend:"base" related:""` // subtype Subtype StructureSubtype `json:"subtype" legend:"base" related:""` // subtype
Type_ StructureType `json:"type" legend:"both" related:""` // type Type_ StructureType `json:"type" legend:"both" related:""` // type
WorshipHfid int `json:"worshipHfid" legend:"base" related:""` // worship_hfid WorshipHfid int `json:"worshipHfid" legend:"base" related:""` // worship_hfid
Ruin bool `json:"ruin" legend:"add" related:""` // Ruin
SiteId int `json:"siteId" legend:"add" related:""` // SiteId SiteId int `json:"siteId" legend:"add" related:""` // SiteId
} }
@ -21542,6 +21548,7 @@ func (x *Structure) MarshalJSON() ([]byte, error) {
if x.WorshipHfid != -1 { if x.WorshipHfid != -1 {
d["worshipHfid"] = x.WorshipHfid d["worshipHfid"] = x.WorshipHfid
} }
d["ruin"] = x.Ruin
if x.SiteId != -1 { if x.SiteId != -1 {
d["siteId"] = x.SiteId d["siteId"] = x.SiteId
} }
@ -21708,6 +21715,7 @@ type WorldConstruction struct {
Id_ int `json:"id" legend:"plus" related:""` // id Id_ int `json:"id" legend:"plus" related:""` // id
Name_ string `json:"name" legend:"plus" related:""` // name Name_ string `json:"name" legend:"plus" related:""` // name
Type_ WorldConstructionType `json:"type" legend:"plus" related:""` // type Type_ WorldConstructionType `json:"type" legend:"plus" related:""` // type
Parts []int `json:"parts" legend:"add" related:""` // Parts
} }
func NewWorldConstruction() *WorldConstruction { func NewWorldConstruction() *WorldConstruction {
@ -21732,6 +21740,7 @@ func (x *WorldConstruction) MarshalJSON() ([]byte, error) {
if x.Type_ != 0 { if x.Type_ != 0 {
d["type"] = x.Type_ d["type"] = x.Type_
} }
d["parts"] = x.Parts
return json.Marshal(d) return json.Marshal(d)
} }

View File

@ -39,6 +39,7 @@ func (w *DfWorld) processEvents() {
case *HistoricalEventCreatedSite: case *HistoricalEventCreatedSite:
w.addEntitySite(d.CivId, d.SiteId) w.addEntitySite(d.CivId, d.SiteId)
w.addEntitySite(d.SiteCivId, d.SiteId) w.addEntitySite(d.SiteCivId, d.SiteId)
w.Sites[d.SiteId].Ruin = false
case *HistoricalEventDestroyedSite: case *HistoricalEventDestroyedSite:
w.addEntitySite(d.DefenderCivId, d.SiteId) w.addEntitySite(d.DefenderCivId, d.SiteId)
w.addEntitySite(d.SiteCivId, d.SiteId) w.addEntitySite(d.SiteCivId, d.SiteId)
@ -48,6 +49,7 @@ func (w *DfWorld) processEvents() {
w.addEntitySite(d.SiteCivId, d.SiteId) w.addEntitySite(d.SiteCivId, d.SiteId)
w.addEntitySite(d.DefenderCivId, d.SiteId) w.addEntitySite(d.DefenderCivId, d.SiteId)
w.addEntitySite(d.NewSiteCivId, d.SiteId) w.addEntitySite(d.NewSiteCivId, d.SiteId)
w.Sites[d.SiteId].Ruin = false
case *HistoricalEventHfDestroyedSite: case *HistoricalEventHfDestroyedSite:
w.addEntitySite(d.SiteCivId, d.SiteId) w.addEntitySite(d.SiteCivId, d.SiteId)
w.addEntitySite(d.DefenderCivId, d.SiteId) w.addEntitySite(d.DefenderCivId, d.SiteId)
@ -74,6 +76,31 @@ func (w *DfWorld) processEvents() {
case *HistoricalEventHfReachSummit: case *HistoricalEventHfReachSummit:
id, _, _ := util.FindInMap(w.MountainPeaks, func(m *MountainPeak) bool { return m.Coords == d.Coords }) id, _, _ := util.FindInMap(w.MountainPeaks, func(m *MountainPeak) bool { return m.Coords == d.Coords })
d.MountainPeakId = id d.MountainPeakId = id
case *HistoricalEventCreatedWorldConstruction:
if master, ok := w.WorldConstructions[d.MasterWcid]; ok {
master.Parts = append(master.Parts, d.Wcid)
}
case *HistoricalEventBuildingProfileAcquired:
if site, ok := w.Sites[d.SiteId]; ok {
if property, ok := site.SiteProperties[d.BuildingProfileId]; ok {
if structure, ok := site.Structures[property.StructureId]; ok {
structure.Ruin = false
}
d.StructureId = property.StructureId
}
}
case *HistoricalEventRazedStructure:
if site, ok := w.Sites[d.SiteId]; ok {
if structure, ok := site.Structures[d.StructureId]; ok {
structure.Ruin = true
}
}
case *HistoricalEventReplacedStructure:
if site, ok := w.Sites[d.SiteId]; ok {
if structure, ok := site.Structures[d.OldAbId]; ok {
structure.Ruin = true
}
}
} }
} }
} }

View File

@ -9,15 +9,21 @@ import (
) )
type Config struct { type Config struct {
path string
LastPath string LastPath string
LastFile string LastFile string
DebugTemplates bool `json:"DebugTemplates,omitempty"`
} }
func LoadConfig() (*Config, error) { func LoadConfig(path string) (*Config, error) {
path, err := configPath() var err error
if path == "" {
path, err = configPath()
if err != nil { if err != nil {
return nil, err return nil, err
} }
}
data, err := ioutil.ReadFile(path) data, err := ioutil.ReadFile(path)
if err != nil { if err != nil {
@ -29,7 +35,7 @@ func LoadConfig() (*Config, error) {
return nil, err return nil, err
} }
return &Config{LastPath: home}, nil return &Config{LastPath: home, path: path}, nil
} else { } else {
return nil, err return nil, err
} }
@ -37,14 +43,21 @@ func LoadConfig() (*Config, error) {
c := &Config{} c := &Config{}
json.Unmarshal(data, c) json.Unmarshal(data, c)
c.path = path
return c, nil return c, nil
} }
func (c *Config) Save() error { func (c *Config) Save() error {
path, err := configPath() var err error
path := c.path
if path == "" {
path, err = configPath()
if err != nil { if err != nil {
return err return err
} }
}
file, err := json.MarshalIndent(c, "", " ") file, err := json.MarshalIndent(c, "", " ")
if err != nil { if err != nil {

View File

@ -89,6 +89,9 @@ func (h loadHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} }
return return
} else { } else {
h.server.context.config.LastFile = p.Current
h.server.context.config.Save()
h.server.context.isLoading = true h.server.context.isLoading = true
h.server.context.world = nil h.server.context.world = nil
go loadWorld(h.server, p.Current) go loadWorld(h.server, p.Current)

View File

@ -28,12 +28,7 @@ type DfServer struct {
context *DfServerContext context *DfServerContext
} }
func StartServer(world *model.DfWorld, static embed.FS) error { func StartServer(config *Config, world *model.DfWorld, static embed.FS) error {
config, err := LoadConfig()
if err != nil {
return err
}
srv := &DfServer{ srv := &DfServer{
router: mux.NewRouter().StrictSlash(true), router: mux.NewRouter().StrictSlash(true),
context: &DfServerContext{ context: &DfServerContext{

View File

@ -39,8 +39,8 @@ func (srv *DfServer) LoadTemplates() {
"structure": func(siteId, id int) template.HTML { return model.LinkStructure(srv.context.world, siteId, id) }, "structure": func(siteId, id int) template.HTML { return model.LinkStructure(srv.context.world, siteId, id) },
"region": func(id int) template.HTML { return model.LinkRegion(srv.context.world, id) }, "region": func(id int) template.HTML { return model.LinkRegion(srv.context.world, id) },
"getRegion": func(id int) *model.Region { return srv.context.world.Regions[id] }, "getRegion": func(id int) *model.Region { return srv.context.world.Regions[id] },
"worldconstruction": func(id int) template.HTML { return model.LinkWorldConstruction(srv.context.world, id) }, "worldConstruction": func(id int) template.HTML { return model.LinkWorldConstruction(srv.context.world, id) },
"getWorldconstruction": func(id int) *model.WorldConstruction { return srv.context.world.WorldConstructions[id] }, "getWorldConstruction": func(id int) *model.WorldConstruction { return srv.context.world.WorldConstructions[id] },
"artifact": func(id int) template.HTML { return model.LinkArtifact(srv.context.world, id) }, "artifact": func(id int) template.HTML { return model.LinkArtifact(srv.context.world, id) },
"getArtifact": func(id int) *model.Artifact { return srv.context.world.Artifacts[id] }, "getArtifact": func(id int) *model.Artifact { return srv.context.world.Artifacts[id] },
"danceForm": func(id int) template.HTML { return model.LinkDanceForm(srv.context.world, id) }, "danceForm": func(id int) template.HTML { return model.LinkDanceForm(srv.context.world, id) },

View File

@ -34,6 +34,14 @@ td.object {
color: #bbb; color: #bbb;
} }
.site.ruin {
color: #b4a675;
}
.structure.ruin {
color: #94702a;
}
.worldconstruction { .worldconstruction {
color: #777777; color: #777777;
} }

View File

@ -1 +1 @@
{{ .Type }} in {{ site .SiteId }} {{ .Type }}{{if .Ruin}} (ruin){{end}} in {{ site .SiteId }}

View File

@ -58,7 +58,7 @@
<div class="col-4"> <div class="col-4">
<h5>WorldConstructions</h5> <h5>WorldConstructions</h5>
<ul> <ul>
{{range .WorldConstructions}}<li>{{ worldconstruction .Id }}</li>{{end}} {{range .WorldConstructions}}<li>{{ worldConstruction .Id }}</li>{{end}}
</ul> </ul>
</div> </div>
{{- end}} {{- end}}

View File

@ -4,7 +4,53 @@
{{define "content"}} {{define "content"}}
<h3>{{ title .Name }}</h3> <h3>{{ title .Name }}</h3>
{{ .Type_ }} <p>{{ .Type_ }}</p>
<nav>
<div class="nav nav-tabs" id="nav-tab" role="tablist">
{{- if gt (len .Structures) 0 }}
<button class="nav-link active" data-bs-toggle="tab" data-bs-target="#nav-structures" type="button" role="tab">Structures</button>
{{- end}}
{{- if gt (len .SiteProperties) 0 }}
<button class="nav-link" data-bs-toggle="tab" data-bs-target="#nav-site-properties" type="button" role="tab">Properties</button>
{{- end}}
</div>
</nav>
<div class="tab-content" id="nav-tabContent">
{{- if gt (len .Structures) 0 }}
<div class="tab-pane active" id="nav-structures" role="tabpanel">
<table class="table table-hover table-sm table-borderless object-table">
<tr>
<th>Name</th>
<th width="100%">Type</th>
</tr>
{{- range .Structures }}
<tr>
<td>{{ structure $.Id .Id }}</td>
<td>{{ .Type }}</td>
</tr>
{{- end}}
</table>
</div>
{{- end}}
{{- if gt (len .SiteProperties) 0 }}
<div class="tab-pane" id="nav-site-properties" role="tabpanel">
<table class="table table-hover table-sm table-borderless object-table">
<tr>
<th>Type</th>
<th width="100%">Name or Owner</th>
</tr>
{{- range .SiteProperties }}
<tr>
<td>{{ if ne .StructureId -1 }}{{ structure $.Id .StructureId }}{{else}}{{ .Type_ }}{{end}}</td>
<td>{{ if ne .OwnerHfid -1 }}{{ hf .OwnerHfid }}{{else}}no
owner{{ end }}</td>
</tr>
{{- end}}
</table>
</div>
{{- end}}
</div>
<h5 class="mt-3">Events</h5> <h5 class="mt-3">Events</h5>
{{ template "events.html" events . }} {{ template "events.html" events . }}

View File

@ -19,12 +19,14 @@
<table class="table table-hover table-sm table-borderless object-table"> <table class="table table-hover table-sm table-borderless object-table">
<tr> <tr>
<th width="100%">Name</th> <th width="100%">Name</th>
<th>Size</th> <th>Structures</th>
<th>Properties</th>
</tr> </tr>
{{- range $v }}{{- if not (eq .Name "") }} {{- range $v }}{{- if not (eq .Name "") }}
<tr> <tr>
<td>{{ site .Id }}</td> <td>{{ site .Id }}</td>
<td></td> <td>{{ len .Structures }}</td>
<td>{{ len .SiteProperties }}</td>
</tr> </tr>
{{- end}}{{- end}} {{- end}}{{- end}}
</table> </table>

View File

@ -5,8 +5,17 @@
{{define "content"}} {{define "content"}}
<h3>{{ title .Name }}</h3> <h3>{{ title .Name }}</h3>
<p>{{ .Type }}</p> <p>{{ .Type }}</p>
<h5>Events</h5>
{{- if gt (len .Parts) 0 }}
<h5>Parts</h5>
<ul>
{{- range .Parts }}
<li>{{ worldConstruction . }}</li>
{{- end }}
</ul>
{{- end }}
<h5>Events</h5>
{{ template "events.html" events . }} {{ template "events.html" events . }}
<p>{{ json . }}</p> <p>{{ json . }}</p>

View File

@ -23,7 +23,7 @@
</tr> </tr>
{{- range $v }}{{- if not (eq .Name "") }} {{- range $v }}{{- if not (eq .Name "") }}
<tr> <tr>
<td>{{ worldconstruction .Id }}</td> <td>{{ worldConstruction .Id }}</td>
<td></td> <td></td>
</tr> </tr>
{{- end}}{{- end}} {{- end}}{{- end}}