multiserver/itemdef.go

411 lines
9.3 KiB
Go
Raw Normal View History

2021-02-10 22:40:42 -08:00
package main
import (
"bytes"
"compress/zlib"
"encoding/binary"
2021-02-23 02:53:16 -08:00
"encoding/json"
2021-02-10 22:40:42 -08:00
"io"
2021-02-13 08:18:27 -08:00
"math"
2021-02-25 02:21:32 -08:00
"strings"
2021-02-10 22:40:42 -08:00
)
var itemdef []byte
var handcapabs map[string]*ToolCapabs
2021-02-10 22:40:42 -08:00
type ItemDef struct {
name string
data []byte
}
// Name returns the name of an ItemDef
func (i *ItemDef) Name() string { return i.name }
// Data returns the actual definition
func (i *ItemDef) Data() []byte { return i.data }
2021-02-13 08:18:27 -08:00
type GroupCap struct {
name string
uses int16
maxLevel int16
times map[int16]float32
}
2021-02-23 02:53:16 -08:00
// newGroupCap returns a partially initialised GroupCap
func newGroupCap(name string, uses, maxLevel int16) *GroupCap {
2021-02-13 08:18:27 -08:00
return &GroupCap{
name: name,
uses: uses,
maxLevel: maxLevel,
times: make(map[int16]float32),
}
}
// Name returns the name of the group
func (g *GroupCap) Name() string { return g.name }
// Uses returns the number of uses
func (g *GroupCap) Uses() int16 { return g.uses }
// MaxLevel returns the maximum level
func (g *GroupCap) MaxLevel() int16 { return g.maxLevel }
// Times returns the digging times
func (g *GroupCap) Times() map[int16]float32 { return g.times }
// SetTimes sets the digging time for a given level
func (g *GroupCap) SetTimes(level int16, time float32) {
g.times[level] = time
}
type ToolCapabs struct {
fullPunchInterval float32
maxDropLevel int16
groupCaps map[string]*GroupCap
damageGroups map[string]int16
punchAttackUses uint16
}
2021-02-23 02:53:16 -08:00
// newToolCapabs initializes and returns ToolCapabs
func newToolCapabs(fullPunchInterval float32, maxDropLevel int16) *ToolCapabs {
2021-02-13 08:18:27 -08:00
return &ToolCapabs{
fullPunchInterval: fullPunchInterval,
maxDropLevel: maxDropLevel,
groupCaps: make(map[string]*GroupCap),
damageGroups: make(map[string]int16),
}
}
// PunchInt returns the full punch interval
func (t *ToolCapabs) PunchInt() float32 { return t.fullPunchInterval }
// MaxDropLevel returns the maximum drop level
func (t *ToolCapabs) MaxDropLevel() int16 { return t.maxDropLevel }
// GroupCaps returns the group capabilities
func (t *ToolCapabs) GroupCaps() map[string]*GroupCap { return t.groupCaps }
// AddGroupCap adds a GroupCap
func (t *ToolCapabs) AddGroupCap(g *GroupCap) {
t.groupCaps[g.Name()] = g
}
// DamageGroups returns the damage groups
func (t *ToolCapabs) DamageGroups() map[string]int16 { return t.damageGroups }
// AddDamageGroup adds a damage group
func (t *ToolCapabs) AddDamageGroup(name string, rating int16) {
t.damageGroups[name] = rating
}
// PunchAttackUses returns the punch attack uses
func (t *ToolCapabs) PunchAttackUses() uint16 { return t.punchAttackUses }
// SetPunchAttackUses sets the punch attack uses
func (t *ToolCapabs) SetPunchAttackUses(uses uint16) {
t.punchAttackUses = uses
}
2021-02-23 02:53:16 -08:00
type GroupCapJSON struct {
2021-02-25 02:21:32 -08:00
MaxLevel int16 `json:"maxlevel"`
Uses int16 `json:"uses"`
2021-02-25 00:11:37 -08:00
Times []float32 `json:"times"`
2021-02-23 02:53:16 -08:00
}
type ToolCapsJSON struct {
2021-02-23 02:56:16 -08:00
FullPunchInterval float32 `json:"full_punch_interval"`
MaxDropLevel int16 `json:"max_drop_level"`
PunchAttackUses uint16 `json:"punch_attack_uses"`
GroupCaps map[string]GroupCapJSON `json:"groupcaps"`
DamageGroups map[string]int16 `json:"damage_groups"`
2021-02-23 02:53:16 -08:00
}
// SerializeJSON returns a serialized JSON string to be used in ItemMeta
2021-02-25 02:21:32 -08:00
func (t *ToolCapabs) SerializeJSON() (s string, err error) {
2021-02-25 00:11:37 -08:00
map2array := func(m map[int16]float32) []float32 {
var maxIndex int
for k := range m {
if int(k) > maxIndex {
maxIndex = int(k)
}
}
2021-02-25 02:21:32 -08:00
r := make([]float32, maxIndex+1)
for k := range r {
r[k] = -1
}
2021-02-25 00:11:37 -08:00
for k, v := range m {
2021-02-25 02:21:32 -08:00
r[int(k)] = v
2021-02-25 00:11:37 -08:00
}
2021-02-25 02:21:32 -08:00
2021-02-25 00:11:37 -08:00
return r
}
2021-02-23 02:53:16 -08:00
gj := make(map[string]GroupCapJSON)
for name, cap := range t.GroupCaps() {
gj[name] = GroupCapJSON{
MaxLevel: cap.MaxLevel(),
2021-02-23 02:56:16 -08:00
Uses: cap.Uses(),
2021-02-25 00:11:37 -08:00
Times: map2array(cap.Times()),
2021-02-23 02:53:16 -08:00
}
}
tj := ToolCapsJSON{
FullPunchInterval: t.PunchInt(),
2021-02-23 02:56:16 -08:00
MaxDropLevel: t.MaxDropLevel(),
PunchAttackUses: t.PunchAttackUses(),
GroupCaps: gj,
DamageGroups: t.DamageGroups(),
2021-02-23 02:53:16 -08:00
}
b, err := json.MarshalIndent(tj, "", "\t")
if err != nil {
2021-02-25 02:21:32 -08:00
return
2021-02-23 02:53:16 -08:00
}
2021-02-25 02:21:32 -08:00
s = strings.Replace(string(b), "-1", "null", -1)
return
2021-02-23 02:53:16 -08:00
}
// DeserializeJSON processes a serialized JSON string
// and updates the ToolCapabs accordingly
func (t *ToolCapabs) DeserializeJSON(ser string) error {
b := []byte(ser)
tj := ToolCapsJSON{}
if err := json.Unmarshal(b, &tj); err != nil {
return err
}
r := newToolCapabs(tj.FullPunchInterval, tj.MaxDropLevel)
r.SetPunchAttackUses(tj.PunchAttackUses)
for name, cap := range tj.GroupCaps {
g := newGroupCap(name, cap.Uses, cap.MaxLevel)
for level, time := range cap.Times {
2021-02-25 00:11:37 -08:00
g.SetTimes(int16(level), time)
2021-02-23 02:53:16 -08:00
}
r.AddGroupCap(g)
}
for g, level := range tj.DamageGroups {
r.AddDamageGroup(g, level)
}
*t = *r
return nil
}
func rmToolCapabs(def []byte) []byte {
2021-04-01 07:05:05 -07:00
r := bytes.NewReader(def)
r.Seek(2, io.SeekStart)
itemNameLen := len(ReadBytes16(r))
desclen := len(ReadBytes16(r))
invImgLen := len(ReadBytes16(r))
wieldImgLen := len(ReadBytes16(r))
r.Seek(16, io.SeekCurrent)
capablen := len(ReadBytes16(r))
stdcaps := []byte{
5,
0, 0, 0, 0,
0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0,
2021-02-13 08:18:27 -08:00
}
si := 28 + itemNameLen + desclen + invImgLen + wieldImgLen
2021-04-01 07:05:05 -07:00
binary.BigEndian.PutUint16(def[si-2:si], uint16(len(stdcaps)))
return append(def[:si], append(stdcaps, def[si+capablen:]...)...)
2021-02-13 08:18:27 -08:00
}
func mergeItemdefs(mgrs map[string][]byte) error {
2021-02-10 22:40:42 -08:00
var itemDefs []*ItemDef
aliases := make(map[string]string)
handcapabs = make(map[string]*ToolCapabs)
var handDef []byte
2021-02-13 08:18:27 -08:00
2021-02-10 22:40:42 -08:00
// Extract definitions from CItemDefManager
for srv, compressedMgr := range mgrs {
2021-02-10 22:40:42 -08:00
zr, err := zlib.NewReader(bytes.NewReader(compressedMgr))
if err != nil {
return err
}
buf := &bytes.Buffer{}
_, err = io.Copy(buf, zr)
if err != nil {
return err
}
zr.Close()
2021-04-01 06:27:22 -07:00
r := bytes.NewReader(buf.Bytes())
r.Seek(1, io.SeekStart)
2021-02-10 22:40:42 -08:00
2021-04-01 06:27:22 -07:00
count := ReadUint16(r)
2021-02-10 22:40:42 -08:00
ItemLoop:
for i := uint16(0); i < count; i++ {
2021-04-01 06:27:22 -07:00
deflen := ReadUint16(r)
2021-02-10 22:40:42 -08:00
2021-04-01 06:27:22 -07:00
def := make([]byte, deflen)
r.Read(def)
2021-02-10 22:40:42 -08:00
2021-04-01 06:27:22 -07:00
dr := bytes.NewReader(def)
dr.Seek(2, io.SeekStart)
2021-04-01 07:05:05 -07:00
itemName := string(ReadBytes16(dr))
2021-04-02 08:24:32 -07:00
ReadBytes16(dr)
ReadBytes16(dr)
ReadBytes16(dr)
dr.Seek(16, io.SeekCurrent)
2021-04-01 06:27:22 -07:00
capablen := ReadUint16(dr)
capab := make([]byte, capablen)
dr.Read(capab)
2021-02-13 08:18:27 -08:00
if capablen > 0 && itemName == "" {
2021-04-01 06:27:22 -07:00
cr := bytes.NewReader(capab)
cr.Seek(1, io.SeekStart)
fpi := math.Float32frombits(ReadUint32(cr))
mdl := int16(ReadUint16(cr))
2021-02-13 08:18:27 -08:00
2021-02-23 02:53:16 -08:00
tcaps := newToolCapabs(fpi, mdl)
2021-02-13 08:18:27 -08:00
2021-04-01 06:27:22 -07:00
grpCapsLen := ReadUint32(cr)
2021-02-13 08:18:27 -08:00
for j := uint32(0); j < grpCapsLen; j++ {
2021-04-01 07:05:05 -07:00
capName := string(ReadBytes16(cr))
uses := int16(ReadUint16(cr))
maxlevel := int16(ReadUint16(cr))
2021-02-13 08:18:27 -08:00
2021-02-23 02:53:16 -08:00
gcap := newGroupCap(capName, uses, maxlevel)
2021-02-13 08:18:27 -08:00
2021-04-01 07:05:05 -07:00
times := ReadUint32(cr)
2021-02-13 08:18:27 -08:00
for k := uint32(0); k < times; k++ {
2021-04-01 07:05:05 -07:00
level := int16(ReadUint16(cr))
times_v := math.Float32frombits(ReadUint32(cr))
2021-02-13 08:18:27 -08:00
gcap.SetTimes(level, times_v)
}
tcaps.AddGroupCap(gcap)
}
2021-04-01 07:05:05 -07:00
dmgGrpCapsLen := ReadUint32(cr)
cr.Seek(4, io.SeekCurrent)
2021-02-13 08:18:27 -08:00
for j := uint32(0); j < dmgGrpCapsLen; j++ {
2021-04-01 07:05:05 -07:00
dmgName := string(ReadBytes16(cr))
rating := int16(ReadUint16(cr))
2021-02-13 08:18:27 -08:00
tcaps.AddDamageGroup(dmgName, rating)
}
2021-04-01 07:05:05 -07:00
tcaps.SetPunchAttackUses(ReadUint16(cr))
2021-02-13 08:18:27 -08:00
if len(handDef) == 0 {
handDef = def
}
handcapabs[srv] = tcaps
2021-02-13 08:18:27 -08:00
2021-04-01 07:05:05 -07:00
def2 := &bytes.Buffer{}
def2.Write(def[:2])
WriteBytes16(def2, []byte("multiserver:hand_"+srv))
def2.Write(def[4+len(itemName):])
2021-02-25 00:11:37 -08:00
itemDefs = append(itemDefs, &ItemDef{
name: "multiserver:hand_" + srv,
2021-04-01 07:05:05 -07:00
data: def2.Bytes(),
2021-02-25 00:11:37 -08:00
})
2021-02-13 08:18:27 -08:00
continue ItemLoop
}
2021-02-10 22:40:42 -08:00
for _, idef := range itemDefs {
if idef.Name() == itemName {
continue ItemLoop
}
}
itemDefs = append(itemDefs, &ItemDef{name: itemName, data: def})
}
2021-04-01 07:05:05 -07:00
aliasCount := ReadUint16(r)
2021-02-10 22:40:42 -08:00
for i := uint16(0); i < aliasCount; i++ {
2021-04-01 07:05:05 -07:00
name := string(ReadBytes16(r))
2021-02-10 22:40:42 -08:00
2021-04-01 07:05:05 -07:00
convert := string(ReadBytes16(r))
2021-02-10 22:40:42 -08:00
if aliases[name] == "" {
aliases[name] = convert
}
}
}
2021-03-06 07:29:14 -08:00
if len(handDef) >= 4 {
2021-02-28 12:45:33 -08:00
handdata := rmToolCapabs(handDef)
2021-02-28 12:45:33 -08:00
var compHanddata bytes.Buffer
handZw := zlib.NewWriter(&compHanddata)
handZw.Write(handdata)
handZw.Close()
2021-02-28 12:45:33 -08:00
hand := &ItemDef{
name: "",
data: handdata,
}
itemDefs = append(itemDefs, hand)
}
2021-02-13 08:18:27 -08:00
2021-02-10 22:40:42 -08:00
// Merge definitions into new CItemDefManager
mgr := make([]byte, 3)
mgr[0] = uint8(0x00)
binary.BigEndian.PutUint16(mgr[1:3], uint16(len(itemDefs)))
var allDefs []byte
for _, def := range itemDefs {
defData := make([]byte, 2+len(def.Data()))
binary.BigEndian.PutUint16(defData[0:2], uint16(len(def.Data())))
copy(defData[2:], def.Data())
allDefs = append(allDefs, defData...)
}
mgr = append(mgr, allDefs...)
aliasCount := make([]byte, 2)
binary.BigEndian.PutUint16(aliasCount, uint16(len(aliases)))
mgr = append(mgr, aliasCount...)
for name, convert := range aliases {
namelen := make([]byte, 2)
binary.BigEndian.PutUint16(namelen, uint16(len(name)))
convertlen := make([]byte, 2)
binary.BigEndian.PutUint16(convertlen, uint16(len(convert)))
mgr = append(mgr, namelen...)
mgr = append(mgr, []byte(name)...)
mgr = append(mgr, convertlen...)
mgr = append(mgr, []byte(convert)...)
}
var compressedMgr bytes.Buffer
zw := zlib.NewWriter(&compressedMgr)
zw.Write(mgr)
zw.Close()
itemdef = compressedMgr.Bytes()
return nil
}