Search Apps Documentation Source Content File Folder Download Copy Actions Download

world_config_store.gno

4.27 Kb · 167 lines
  1package personal_world
  2
  3import "gno.land/p/akkadia/v0/ds/btree"
  4
  5var worldConfigStore *WorldConfigStore = newWorldConfigStore()
  6
  7// WorldConfigStore owns personal world biome and size configuration records.
  8//
  9// Data shape:
 10// - biomeInfos: biome(string) -> map[string]string
 11// - sizeInfos: sizeID(string) -> map[string]string
 12type WorldConfigStore struct {
 13	biomeInfos   *btree.StringBTree
 14	defaultBiome string
 15	sizeInfos    *btree.StringBTree
 16}
 17
 18func newWorldConfigStore() *WorldConfigStore {
 19	return &WorldConfigStore{
 20		biomeInfos:   btree.NewStringBTree(32),
 21		defaultBiome: "",
 22		sizeInfos:    btree.NewStringBTree(32),
 23	}
 24}
 25
 26// ==================== DANGER: MUTABLE MIGRATION CAPABILITIES ====================
 27//
 28// The getters in this section expose mutable store internals.
 29// Only authorized migration exporter paths may depend on these capabilities.
 30// Runtime reads and test setup must use copy-returning methods or total helpers.
 31func (s *WorldConfigStore) BiomeInfos() *btree.StringBTree {
 32	return s.biomeInfos
 33}
 34
 35func (s *WorldConfigStore) SizeInfos() *btree.StringBTree {
 36	return s.sizeInfos
 37}
 38
 39// ================= END DANGER: MUTABLE MIGRATION CAPABILITIES ==================
 40
 41func (s *WorldConfigStore) SetBiomeInfo(info map[string]string) map[string]string {
 42	biomeName := info["biome"]
 43	s.biomeInfos.Set(biomeName, copyStringMap(info))
 44	return copyStringMap(info)
 45}
 46
 47func (s *WorldConfigStore) MustGetBiomeInfo(biomeName string) map[string]string {
 48	info, found := s.GetBiomeInfo(biomeName)
 49	if !found {
 50		panic("biome not found: " + biomeName)
 51	}
 52	return info
 53}
 54
 55func (s *WorldConfigStore) GetBiomeInfo(biomeName string) (map[string]string, bool) {
 56	info, found := s.biomeInfos.Get(biomeName)
 57	if !found {
 58		return nil, false
 59	}
 60	return copyStringMap(info.(map[string]string)), true
 61}
 62
 63func (s *WorldConfigStore) ListBiomeInfos() []map[string]string {
 64	result := []map[string]string{}
 65	s.biomeInfos.Iterate(nil, nil, func(_ string, info any) bool {
 66		result = append(result, copyStringMap(info.(map[string]string)))
 67		return false
 68	})
 69	return result
 70}
 71
 72func (s *WorldConfigStore) HasBiomeInfo(biomeName string) bool {
 73	return s.biomeInfos.Has(biomeName)
 74}
 75
 76func (s *WorldConfigStore) SetDefaultBiome(biomeName string) string {
 77	oldDefault := s.defaultBiome
 78	s.defaultBiome = biomeName
 79	return oldDefault
 80}
 81
 82func (s *WorldConfigStore) DefaultBiome() string {
 83	return s.defaultBiome
 84}
 85
 86func (s *WorldConfigStore) TotalBiomes() int {
 87	return s.biomeInfos.Size()
 88}
 89
 90func (s *WorldConfigStore) SetSizeInfo(info map[string]string) map[string]string {
 91	key := info["id"]
 92	s.sizeInfos.Set(key, copyStringMap(info))
 93	return copyStringMap(info)
 94}
 95
 96func (s *WorldConfigStore) MustGetSizeInfo(sizeID string) map[string]string {
 97	info, found := s.GetSizeInfo(sizeID)
 98	if !found {
 99		panic("size info not found: " + sizeID)
100	}
101	return info
102}
103
104func (s *WorldConfigStore) GetSizeInfo(sizeID string) (map[string]string, bool) {
105	info, found := s.sizeInfos.Get(sizeID)
106	if !found {
107		return nil, false
108	}
109	return copyStringMap(info.(map[string]string)), true
110}
111
112func (s *WorldConfigStore) ListSizeInfos() []map[string]string {
113	result := []map[string]string{}
114	s.sizeInfos.Iterate(nil, nil, func(_ string, info any) bool {
115		result = append(result, copyStringMap(info.(map[string]string)))
116		return false
117	})
118	return result
119}
120
121func (s *WorldConfigStore) TotalSizes() int {
122	return s.sizeInfos.Size()
123}
124
125func calculateExpansionCost(baseCost int64, priceMultiplierBPS int64) (int64, bool) {
126	if baseCost <= 0 {
127		return 0, true
128	}
129	if priceMultiplierBPS < 0 {
130		return maxInt64, false
131	}
132
133	denominator := int64(10000)
134	wholeAmount := baseCost / denominator
135	remainingAmount := baseCost % denominator
136	first, ok := checkedMultiply(wholeAmount, priceMultiplierBPS)
137	if !ok {
138		return maxInt64, false
139	}
140	second, ok := checkedMultiply(remainingAmount, priceMultiplierBPS)
141	if !ok {
142		return maxInt64, false
143	}
144	second = second / denominator
145	total, ok := checkedAdd(first, second)
146	if !ok {
147		return maxInt64, false
148	}
149	return total, true
150}
151
152func checkedMultiply(a int64, b int64) (int64, bool) {
153	if a == 0 || b == 0 {
154		return 0, true
155	}
156	if a < 0 || b < 0 || a > maxInt64/b {
157		return maxInt64, false
158	}
159	return a * b, true
160}
161
162func checkedAdd(a int64, b int64) (int64, bool) {
163	if a < 0 || b < 0 || a > maxInt64-b {
164		return maxInt64, false
165	}
166	return a + b, true
167}