代码初始化

This commit is contained in:
Giao committed 2026-10-09 18:23:57 +08:00
1 parent c2f5cd98ff
commit e3efeb74ad
2439 files changed
+305661 -1

No files matched your search

+96
View File
@@ -0,0 +1,96 @@
# -*- coding: utf-8 -*-
"""将 8 个纯贴图医疗物品加入网易基岩版模组(与 _tmp/add_materials.py 同风格)"""
import os, json, shutil
ROOT = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02'
BP = os.path.join(ROOT, 'behavior_pack_kcH4M5u0')
RP = os.path.join(ROOT, 'resource_pack_t7eJjrxY')
TEX_SRC = os.path.join(ROOT, '_sa_medical_textures')
# id, 中文名, 说明(tooltip)
ITEMS = [
('plaster', '创可贴', '医疗用品,用于轻度包扎治疗。'),
('splint', '夹板', '医疗用品,用于固定骨折部位。'),
('alcohol_wipes', '酒精湿巾', '医疗用品,用于消毒。'),
('blood_bag', '血袋', '医疗用品,用于输血补血。'),
('blood_bag_empty', '空血袋', '空的血袋,可用于采集血液。'),
('painkiller_pills', '止痛药丸', '口服止痛药,可缓解疼痛。'),
('stamina_boost_pills', '耐力增强药丸', '口服增强药,可提升耐力。'),
('tube', '管子', '医疗用品,用于输液。'),
]
# 1) 复制贴图
tex_dst = os.path.join(RP, 'textures', 'items')
for i, _, _ in ITEMS:
shutil.copyfile(os.path.join(TEX_SRC, i + '.png'), os.path.join(tex_dst, i + '.png'))
# 2) 行为包物品 json
for i, _, tip in ITEMS:
obj = {
"format_version": "1.10",
"minecraft:item": {
"components": {
"minecraft:max_stack_size": 64,
"netease:customtips": {"value": tip}
},
"description": {
"category": "dn_sa",
"identifier": "dn_sa:" + i
}
}
}
with open(os.path.join(BP, 'netease_items_beh', 'dn_sa_%s.json' % i), 'w', encoding='utf-8') as f:
json.dump(obj, f, ensure_ascii=False, indent=4)
# 3) 资源包物品 json
for i, _, _ in ITEMS:
obj = {
"format_version": "1.10",
"minecraft:item": {
"components": {"minecraft:icon": "dn_sa:" + i},
"description": {"identifier": "dn_sa:" + i}
}
}
with open(os.path.join(RP, 'netease_items_res', 'dn_sa_%s.json' % i), 'w', encoding='utf-8') as f:
json.dump(obj, f, ensure_ascii=False, indent=4)
# 4) item_texture.json 登记
itp = os.path.join(RP, 'textures', 'item_texture.json')
with open(itp, encoding='utf-8') as f:
data = json.load(f)
td = data['texture_data']
for i, _, _ in ITEMS:
td['dn_sa:' + i] = {"textures": "textures/items/" + i}
with open(itp, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=4)
# 5) group_config.json 新增医疗分组
gc = os.path.join(BP, 'netease_group', 'group_config.json')
with open(gc, encoding='utf-8') as f:
gdata = json.load(f)
names = [g['group_name'] for g in gdata['groups']]
if 'itemGroup.name.dn_sa_med' not in names:
gdata['groups'].append({
"group_name": "itemGroup.name.dn_sa_med",
"icon": "dn_sa:plaster",
"list": ["dn_sa:" + i for i, _, _ in ITEMS]
})
with open(gc, 'w', encoding='utf-8') as f:
json.dump(gdata, f, ensure_ascii=False, indent=2)
# 6) zh_CN.lang
lang = os.path.join(RP, 'texts', 'zh_CN.lang')
with open(lang, encoding='utf-8') as f:
lines = f.read().rstrip('\n').split('\n')
existing = set(l.split('=')[0] for l in lines if '=' in l)
add = []
if 'itemGroup.name.dn_sa_med' not in existing:
add.append('itemGroup.name.dn_sa_med=医疗用品')
for i, cn, _ in ITEMS:
k = 'item.dn_sa:%s.name' % i
if k not in existing:
add.append('%s=%s' % (k, cn))
with open(lang, 'w', encoding='utf-8') as f:
f.write('\n'.join(lines) + '\n\n' + '\n'.join(add) + '\n')
print('OK: %d items' % len(ITEMS))
File diff suppressed because it is too large. Load diff
+71
View File
@@ -0,0 +1,71 @@
# -*- coding: utf-8 -*-
"""审计三个 jar 的语言文件覆盖情况:
1) 资源(br blockstates / models.item)有、但 lang 缺 key 的(游戏内显示原始 key)
2) en_us 有、zh_cn 缺(未汉化)
"""
import zipfile, json, io, sys, os
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
BASE = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02\_sa_hanhua_out'
JARS = ['sa_essentials-forge-1.20.1-1.0.0.jar',
'sa_lib-forge-1.20.1-1.0.1.jar',
'sa_decor-forge-1.20.1-1.0.3.jar']
for jn in JARS:
p = os.path.join(BASE, jn)
if not os.path.exists(p):
continue
z = zipfile.ZipFile(p)
names = z.namelist()
# 命名空间
ass_roots = sorted({n.split('/')[1] for n in names if n.startswith('assets/') and len(n.split('/')) > 2})
print('=' * 70)
print('JAR:', jn, ' namespaces:', ass_roots)
for ns in ass_roots:
prefix = 'assets/%s/' % ns
langfiles = {}
for n in names:
if n.startswith(prefix + 'lang/') and n.endswith('.json'):
loc = os.path.basename(n)[:-5]
langfiles[loc] = json.loads(z.read(n).decode('utf-8-sig'))
bs = sorted(os.path.basename(n)[:-5] for n in names
if n.startswith(prefix + 'blockstates/') and n.endswith('.json'))
im = sorted(os.path.basename(n)[:-5] for n in names
if n.startswith(prefix + 'models/item/') and n.endswith('.json'))
en = langfiles.get('en_us', {})
zh = langfiles.get('zh_cn', {})
print('-' * 60)
print('[%s] lang=%s blocks=%d item_models=%d' % (ns, sorted(langfiles), len(bs), len(im)))
miss_en = [b for b in bs if ('block.%s.%s' % (ns, b)) not in en and ('item.%s.%s' % (ns, b)) not in en]
miss_zh = [b for b in bs if ('block.%s.%s' % (ns, b)) not in zh and ('item.%s.%s' % (ns, b)) not in zh]
miss_i_en = [i for i in im if ('item.%s.%s' % (ns, i)) not in en and ('block.%s.%s' % (ns, i)) not in en]
miss_i_zh = [i for i in im if ('item.%s.%s' % (ns, i)) not in zh and ('block.%s.%s' % (ns, i)) not in zh]
def show(t, l):
if l:
print(' %s (%d): %s' % (t, len(l), ', '.join(l[:60])))
else:
print(' %s (0)' % t)
show('方块 资源有/zh_cn缺', miss_zh)
show('方块 资源有/en_us缺', miss_en)
show('物品 资源有/zh_cn缺', miss_i_zh)
show('物品 资源有/en_us缺', miss_i_en)
# en 有 zh 缺
if en and zh:
only_en = sorted(k for k in en if k not in zh)
if only_en:
print(' en_us 有 / zh_cn 缺 (%d): %s' % (len(only_en), ', '.join(only_en[:60])))
# zh 是英文原文(未翻译)的 key
same = sorted(k for k in zh if k in en and zh[k] == en[k] and any(c.isalpha() for c in zh[k]))
if same:
print(' zh_cn 内容仍是英文 (%d): %s' % (len(same), ', '.join(same[:60])))
z.close()
@@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
import zipfile, json, os, io, sys, subprocess, re
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
base = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02\_sa_hanhua_out'
tmp = os.path.join(base, '_tmp', 'regjavap')
os.makedirs(tmp, exist_ok=True)
z = zipfile.ZipFile(os.path.join(base, 'sa_lib-forge-1.20.1-1.0.1.jar'))
en = json.loads(z.read('assets/sa_core/lang/en_us.json').decode('utf-8-sig'))
zh = json.loads(z.read('assets/sa_core/lang/zh_cn.json').decode('utf-8-sig'))
name_re = re.compile(r'^[a-z][a-z0-9_]{2,}$')
found = set()
for cls in ['com/ogaba/sacore/registry/ModItems.class', 'com/ogaba/sacore/registry/ModBlocks.class']:
out = os.path.join(tmp, 'sacore__' + cls.replace('/', '_'))
with open(out, 'wb') as f:
f.write(z.read(cls))
txt = subprocess.run(['javap', '-p', '-c', out], capture_output=True).stdout.decode('utf-8', 'ignore')
for m in re.finditer(r'// String (.+)$', txt, re.M):
s = m.group(1).strip().strip('"')
if name_re.match(s):
found.add(s)
print('sa_core names:', len(found))
miss = sorted(s for s in found if ('block.sa_core.' + s) not in en and ('item.sa_core.' + s) not in en)
print('missing lang:', miss)
onlyen = sorted(k for k in en if k not in zh)
print('en 有 zh 缺:', onlyen)
print('zh 仍是英文:', sorted(k for k in zh if k in en and zh[k] == en[k] and any(c.isalpha() for c in zh[k])))
k = 'tooltip.sa_core.jerry_can.amount'
print('jerry_can.amount EN =', repr(en.get(k)))
print('jerry_can.amount ZH =', repr(zh.get(k)))
# jerry_can_using 资源
names = z.namelist()
print('jerry_can_using blockstate:', 'assets/sa_core/blockstates/jerry_can_using.json' in names)
print('jerry_can_using itemmodel:', 'assets/sa_core/models/item/jerry_can_using.json' in names)
+17
View File
@@ -0,0 +1,17 @@
# -*- coding: utf-8 -*-
import os, json
ROOT = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02'
bad = []
for pack in ['behavior_pack_kcH4M5u0', 'resource_pack_t7eJjrxY']:
for dp, dn, fn in os.walk(os.path.join(ROOT, pack)):
for n in fn:
if n.endswith('.json'):
p = os.path.join(dp, n)
try:
with open(p, encoding='utf-8') as f:
json.load(f)
except Exception as e:
bad.append('%s :: %s' % (os.path.relpath(p, ROOT), e))
with open(os.path.join(ROOT, '_sa_hanhua_out', '_tmp', 'json_check.txt'), 'w', encoding='utf-8') as f:
f.write('\n'.join(bad) if bad else 'ALL JSON OK')
print('bad=%d' % len(bad))
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
import zipfile, json, io, sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
base = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02\_sa_hanhua_out'
z = zipfile.ZipFile(base + r'\sa_decor-forge-1.20.1-1.0.3.jar')
en = json.loads(z.read('assets/sa_decor/lang/en_us.json').decode('utf-8-sig'))
zh = json.loads(z.read('assets/sa_decor/lang/zh_cn.json').decode('utf-8-sig'))
for k in ['text.sa_decor.loot_prompt_locked_suffix', 'tooltip.sa_decor.gas_barrel.amount']:
print('DECOR', k)
print(' EN:', repr(en.get(k)))
print(' ZH:', repr(zh.get(k)))
z2 = zipfile.ZipFile(base + r'\sa_essentials-forge-1.20.1-1.0.0.jar')
en2 = json.loads(z2.read('assets/sa_combat/lang/en_us.json').decode('utf-8-sig'))
zh2 = json.loads(z2.read('assets/sa_combat/lang/zh_cn.json').decode('utf-8-sig'))
for k in ['block.sa_combat.c4', 'blueprint.sa_combat.c4']:
print('COMBAT', k)
print(' EN:', repr(en2.get(k)))
print(' ZH:', repr(zh2.get(k)))
@@ -0,0 +1,94 @@
# -*- coding: utf-8 -*-
import re, zipfile, json, collections, os
ROOT = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02'
TABLE = os.path.join(ROOT, '\u5e78\u5b58\u8005\u519b\u706b\u5e93-\u65b9\u5757\u603b\u8868.md')
JAR = os.path.join(ROOT, '_sa_hanhua_out', 'sa_decor-forge-1.20.1-1.0.3.jar')
# ---- parse table ----
cat = None
blocks = [] # (category, id, en, zh, note, mod)
with open(TABLE, encoding='utf-8') as f:
for line in f:
line = line.rstrip('\n')
m = re.match(r'^\*\*(.+?)\*\*$', line.strip())
if m:
cat = m.group(1).strip()
continue
m = re.match(r'^\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]*?)\s*\|\s*([^|]*?)\s*\|\s*([^|]*?)\s*\|\s*$', line)
if not m:
continue
c, bid, en, zh, note, mod = [x.strip() for x in m.groups()]
if c in ('\u5206\u7c7b',): # header
continue
if bid in ('\u88f8ID',):
continue
if mod != 'sa_decor':
continue
blocks.append((cat, bid, en, zh, note, mod))
print('sa_decor blocks in table:', len(blocks))
print('categories:', collections.Counter(b[0] for b in blocks))
ids = [b[1] for b in blocks]
dup = [k for k, v in collections.Counter(ids).items() if v > 1]
print('duplicate ids:', dup)
# ---- jar entries ----
z = zipfile.ZipFile(JAR)
names = z.namelist()
tex = [x for x in names if x.startswith('assets/sa_decor/textures/block/') and x.endswith('.png')]
mod = [x for x in names if x.startswith('assets/sa_decor/models/block/') and x.endswith('.json')]
def subfolder(x, kind):
rest = x.split('/block/', 1)[1]
parts = rest.split('/')
return parts[0] if len(parts) > 1 else '(root)'
mod_folders = collections.Counter(subfolder(x, 'm') for x in mod)
tex_folders = collections.Counter(subfolder(x, 't') for x in tex)
print('--- model folders (name:count) ---')
for k in sorted(mod_folders):
print(' M', k, mod_folders[k])
print('--- texture folders (name:count) ---')
for k in sorted(tex_folders):
print(' T', k, tex_folders[k])
# ---- match each block id to model folder ----
def best_folder(bid, folders):
cands = [f for f in folders if f != '(root)']
exact = [f for f in cands if f == bid]
if exact:
return exact[0]
# folder is prefix of id
pref = [f for f in cands if bid.startswith(f + '_')]
if pref:
return max(pref, key=len)
# id is prefix of folder
pref2 = [f for f in cands if f.startswith(bid + '_')]
if pref2:
return max(pref2, key=len)
return None
res = []
unmatched = []
for c, bid, en, zh, note, m in blocks:
mf = best_folder(bid, mod_folders)
tf = best_folder(bid, tex_folders)
res.append((c, bid, mf, tf))
if mf is None:
unmatched.append(('model', c, bid))
print('=== unmatched model ===')
for u in unmatched:
print(u)
# folders never assigned
used_m = set(r[2] for r in res if r[2])
print('=== model folders not used ===')
for f in sorted(mod_folders):
if f != '(root)' and f not in used_m:
print(' ', f, mod_folders[f])
print('=== model root files ===', mod_folders.get('(root)'))
for x in mod:
if subfolder(x, 'm') == '(root)':
print(' ', x.split('/block/', 1)[1])
File diff suppressed because it is too large. Load diff
+55
View File
@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
import re, zipfile, collections, os, json
ROOT = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02'
TABLE = os.path.join(ROOT, '\u5e78\u5b58\u8005\u519b\u706b\u5e93-\u65b9\u5757\u603b\u8868.md')
JAR = os.path.join(ROOT, '_sa_hanhua_out', 'sa_decor-forge-1.20.1-1.0.3.jar')
cat = None
bid2cat = {}
for line in open(TABLE, encoding='utf-8'):
line = line.rstrip('\n').strip()
m = re.match(r'^\*\*(.+?)\*\*$', line)
if m:
cat = m.group(1).strip(); continue
m = re.match(r'^\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]*?)\s*\|\s*([^|]*?)\s*\|\s*([^|]*?)\s*\|\s*$', line)
if not m: continue
c, bid, en, zh, note, mod = [x.strip() for x in m.groups()]
if mod != 'sa_decor': continue
bid2cat.setdefault(bid, c)
ids = list(bid2cat)
z = zipfile.ZipFile(JAR)
names = z.namelist()
def folders(prefix, ext):
d = collections.defaultdict(list)
for x in names:
if x.startswith(prefix) and x.endswith(ext):
rest = x.split(prefix, 1)[1]
parts = rest.split('/')
d[parts[0] if len(parts) > 1 else '(root)'].append(rest)
return d
mf = folders('assets/sa_decor/models/block/', '.json')
tf = folders('assets/sa_decor/textures/block/', '.png')
def match_cats(name):
res = collections.Counter()
for b, c in bid2cat.items():
if name == b or b.startswith(name + '_') or name.startswith(b + '_') \
or name.endswith('_' + b) or b.endswith('_' + name):
res[c] += 1
return res
print('===== MODEL FOLDERS =====')
for f in sorted(mf):
if f == '(root)': continue
print(f'{f}\t{len(mf[f])}\t{dict(match_cats(f))}')
print('===== TEXTURE FOLDERS =====')
for f in sorted(tf):
if f == '(root)': continue
print(f'{f}\t{len(tf[f])}\t{dict(match_cats(f))}')
print('===== ROOT MODEL FILES =====')
for x in sorted(mf['(root)']):
base = x[:-5]
print(f'{base}\t{dict(match_cats(base))}')
@@ -0,0 +1,173 @@
# -*- coding: utf-8 -*-
"""sa_decor 装饰方块归档 v2:
- 每个分类目录下保留原始 pack 层级:textures/block/... 与 models/block/...
- 保证模型内 sa_decor:block/... 引用在其所在分类目录中能找到(含 parent 链闭包)
"""
import re, zipfile, collections, os, shutil, json
ROOT = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02'
TABLE = os.path.join(ROOT, '\u5e78\u5b58\u8005\u519b\u706b\u5e93-\u65b9\u5757\u603b\u8868.md')
JAR = os.path.join(ROOT, '_sa_hanhua_out', 'sa_decor-forge-1.20.1-1.0.3.jar')
TEX_OUT = os.path.join(ROOT, '_sa_decor_textures')
MOD_OUT = os.path.join(ROOT, '_sa_decor_models')
CAT_ORDER = ['围栏', '家具', '容器', '屋顶', '市政设施', '建材', '杂物', '标牌', '灯具', '装饰', '路障', '载具', '门', '其它']
CAT_DIR = {c: f'{i+1:02d}_{c}' for i, c in enumerate(CAT_ORDER)}
# ---------- 解析总表 ----------
cat = None; rows = []; seen = set()
for line in open(TABLE, encoding='utf-8'):
line = line.rstrip('\n').strip()
m = re.match(r'^\*\*(.+?)\*\*$', line)
if m: cat = m.group(1).strip(); continue
m = re.match(r'^\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]*?)\s*\|\s*([^|]*?)\s*\|\s*([^|]*?)\s*\|\s*$', line)
if not m: continue
c, bid, en, zh, note, mod = [x.strip() for x in m.groups()]
if mod != 'sa_decor' or (c, bid) in seen: continue
seen.add((c, bid)); rows.append((c, bid, en, zh, note))
bid2cat = {}
for c, bid, en, zh, note in rows: bid2cat.setdefault(bid, c)
SPLIT = {'asphalt', 'cinder_block', 'duct', 'storefront', 'construction_barrier', 'metal_counter', 'road_sign'}
MOD_OVERRIDE = {'bricks':'建材','decor_bench':'家具','doors':'门','double_flourecent_rod':'灯具','flags':'装饰','mattress':'家具','street_light_post':'灯具','floor_mirror':'建材','urban_fence_door':'门'}
TEX_OVERRIDE = {'beartrap':'装饰','bloodprops':'杂物','bricks':'建材','doors':'门','flags':'装饰','hatchback':'载具','lootcrates':'容器','mechanical':'其它','particle':'其它','particles':'其它','storefront':None,'vehicles':'载具'}
def geo_cat(rel):
stem = rel[:-len('.geo.json')] if rel.endswith('.geo.json') else os.path.splitext(rel)[0]
low = stem.lower()
toks = set(re.split(r'[_\d]+', low))
if 'garage_door' in low: return '门'
if toks & {'car','pickup','sedan','van','police','ambulance','hatchback'}: return '载具'
if low.startswith('lying_corpse') or 'keycard' in low: return '装饰'
return '其它'
ROOT_EXTRA = {'generator':'其它','guns':'其它','counter':'容器','framed':'屋顶','flourecent_rod':'灯具','corpse1':'装饰','tires':'装饰','wooden_pallet':'装饰','wood_particle':'其它','wire_item':'装饰','plastic_red':'家具','plastic_white':'家具','plastic_whitered':'家具','spruce_table':'家具','road_barrier':'装饰','road_barrier_big':'装饰','water_fountain':'市政设施','construction_barrier1':'路障','toilet2':'装饰','barbed_wire2':'装饰','folding_chair1':'家具','street_light_pole':'灯具','military_bed1':'家具','floor_mirror_black':'建材','gutter_inner':'装饰','broken_glass1':'装饰','traffic_cone1':'装饰','woodentable':'家具'}
def auto_cat(name):
v = collections.Counter()
for b, c in bid2cat.items():
if name == b or b.startswith(name+'_') or name.startswith(b+'_') or name.endswith('_'+b) or b.endswith('_'+name):
v[c] += 1
if not v: return None
top = max(v.values())
for c in CAT_ORDER:
if v.get(c,0) == top: return c
return None
def split_rule(f, b):
b = b.lower()
if f=='asphalt': return '灯具' if 'light_asphalt' in b else '建材'
if f=='cinder_block': return '建材' if '_wall' in b else '装饰'
if f=='duct': return '门' if 'trapdoor' in b else '建材'
if f=='storefront': return '门' if ('door' in b or 'header' in b) else '建材'
if f=='construction_barrier': return '灯具' if 'no_lamp' in b else '路障'
if f=='metal_counter': return '容器' if 'wall' in b else '装饰'
if f=='road_sign': return '灯具' if 'traffic_light' in b else '标牌'
return None
def resolve(kind, rel):
folder = rel.split('/')[0] if '/' in rel else '(root)'
base = os.path.splitext(os.path.basename(rel))[0]
if folder == '(root)':
return auto_cat(base) or ROOT_EXTRA.get(base) or auto_cat(re.sub(r'\d+$','',base)) or '其它'
ov = MOD_OVERRIDE if kind=='model' else TEX_OVERRIDE
if folder in ov and ov[folder]: return ov[folder]
if folder in SPLIT or (kind=='texture' and folder=='storefront'):
c = split_rule(folder, base)
if c: return c
return auto_cat(folder) or '其它'
# ---------- 清空旧输出 ----------
for d in (TEX_OUT, MOD_OUT):
if os.path.isdir(d): shutil.rmtree(d)
z = zipfile.ZipFile(JAR)
names = z.namelist()
tex_block = [x.split('textures/block/',1)[1] for x in names if x.startswith('assets/sa_decor/textures/block/') and x.endswith('.png')]
tex_item = [x.split('textures/item/',1)[1] for x in names if x.startswith('assets/sa_decor/textures/item/') and x.endswith('.png')]
mod_block = [x.split('models/block/',1)[1] for x in names if x.startswith('assets/sa_decor/models/block/') and x.endswith('.json')]
geo_block = [x.split('geo/block/',1)[1] for x in names if x.startswith('assets/sa_decor/geo/block/') and x.endswith('.json')]
TB = set(tex_block); TI = set(tex_item); MB = set(mod_block); GB = set(geo_block)
REF = re.compile(r'sa_decor:(block|item)/([A-Za-z0-9_/.\-]+)')
writes = collections.Counter() # (cat, kind) -> 写入次数
groups = collections.Counter() # (kind, cat, group) -> 次数
copied = set() # 已写目标路径,避免重复
ref_extra = 0
def w(zpath, dest):
if dest in copied: return
copied.add(dest)
os.makedirs(os.path.dirname(dest), exist_ok=True)
with z.open(zpath) as s, open(dest, 'wb') as f:
shutil.copyfileobj(s, f)
def put_texture(cat, typ, rel):
dest = os.path.join(TEX_OUT, CAT_DIR[cat], 'textures', typ, rel)
w('assets/sa_decor/textures/%s/%s' % (typ, rel), dest)
writes[(cat, 'texture')] += 1
fam = rel.split('/')[0] if '/' in rel else '(root)'
groups[('texture', cat, 'textures/%s/%s' % (typ, fam))] += 1
def put_model(cat, rel, geo=False):
dest = os.path.join(MOD_OUT, CAT_DIR[cat], 'models', 'block', ('_geo/' + rel) if geo else rel)
w('assets/sa_decor/%s/block/%s' % ('geo' if geo else 'models', rel), dest)
writes[(cat, 'model')] += 1
fam = rel.split('/')[0] if '/' in rel else '(root)'
groups[('model', cat, ('_geo/' + fam) if geo else fam)] += 1
def closure_for_model(cat, rel, geo=False):
"""把该模型引用到的贴图/父模型补进同一分类目录"""
global ref_extra
txt = z.read('assets/sa_decor/%s/block/%s' % ('geo' if geo else 'models', rel)).decode('utf-8', 'ignore')
stack = list(REF.findall(txt))
seen_ref = set()
while stack:
typ, p = stack.pop()
if (typ, p) in seen_ref: continue
seen_ref.add((typ, p))
if typ == 'block':
if p + '.png' in TB:
before = os.path.join(TEX_OUT, CAT_DIR[cat], 'textures', 'block', p + '.png') in copied
put_texture(cat, 'block', p + '.png')
if not before: ref_extra += 1
elif p + '.json' in MB:
before = os.path.join(MOD_OUT, CAT_DIR[cat], 'models', 'block', p + '.json') in copied
put_model(cat, p + '.json')
if not before:
ref_extra += 1
sub = z.read('assets/sa_decor/models/block/' + p + '.json').decode('utf-8','ignore')
stack.extend(REF.findall(sub))
elif p + '.json' in GB:
before = os.path.join(MOD_OUT, CAT_DIR[cat], 'models', 'block', '_geo', p + '.json') in copied
put_model(cat, p + '.json', geo=True)
if not before:
ref_extra += 1
sub = z.read('assets/sa_decor/geo/block/' + p + '.json').decode('utf-8','ignore')
stack.extend(REF.findall(sub))
else: # item
if p + '.png' in TI:
before = os.path.join(TEX_OUT, CAT_DIR[cat], 'textures', 'item', p + '.png') in copied
put_texture(cat, 'item', p + '.png')
if not before: ref_extra += 1
# ---- 1. 自身分类全量归档 ----
for rel in tex_block: put_texture(resolve('texture', rel), 'block', rel)
for rel in tex_item: put_texture(resolve('texture', rel), 'item', rel)
for rel in mod_block: put_model(resolve('model', rel), rel)
for rel in geo_block: put_model(geo_cat(rel), rel, geo=True)
# ---- 2. 引用闭包:补进模型所在分类 ----
for rel in mod_block: closure_for_model(resolve('model', rel), rel)
for rel in geo_block: closure_for_model(geo_cat(rel), rel, geo=True)
print('=== 分类统计 贴图/模型(含引用补入) ===')
for c in CAT_ORDER:
print(' %s: 贴图 %d / 模型 %d' % (c, writes[(c,'texture')], writes[(c,'model')]))
print('引用补入文件数:', ref_extra, ' 总写入文件数:', len(copied))
print('其它目录内容:', [r for r in tex_block + tex_item if resolve('texture', r) == '其它'])
json.dump({'rows': rows,
'rec': {f'{c}|{k}': v for (c,k), v in writes.items()},
'folders': {f'{k}|{c}|{g}': v for (k,c,g), v in groups.items()}},
open(os.path.join(ROOT, '_sa_hanhua_out', '_tmp', 'decor_archive_result.json'), 'w', encoding='utf-8'),
ensure_ascii=False, indent=1)
print('DONE')
@@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
"""诊断:模型内 sa_decor:block/... 引用在新归档中是否丢失/跨分类。"""
import re, zipfile, collections, os
ROOT = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02'
TABLE = os.path.join(ROOT, '\u5e78\u5b58\u8005\u519b\u706b\u5e93-\u65b9\u5757\u603b\u8868.md')
JAR = os.path.join(ROOT, '_sa_hanhua_out', 'sa_decor-forge-1.20.1-1.0.3.jar')
CAT_ORDER = ['围栏', '家具', '容器', '屋顶', '市政设施', '建材', '杂物', '标牌', '灯具', '装饰', '路障', '载具', '门', '其它']
cat = None; rows = []; seen = set()
for line in open(TABLE, encoding='utf-8'):
line = line.rstrip('\n').strip()
m = re.match(r'^\*\*(.+?)\*\*$', line)
if m: cat = m.group(1).strip(); continue
m = re.match(r'^\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]+?)\s*\|\s*([^|]*?)\s*\|\s*([^|]*?)\s*\|\s*([^|]*?)\s*\|\s*$', line)
if not m: continue
c, bid, en, zh, note, mod = [x.strip() for x in m.groups()]
if mod != 'sa_decor' or (c, bid) in seen: continue
seen.add((c, bid)); rows.append((c, bid, en, zh, note))
bid2cat = {}
for c, bid, en, zh, note in rows: bid2cat.setdefault(bid, c)
SPLIT = {'asphalt', 'cinder_block', 'duct', 'storefront', 'construction_barrier', 'metal_counter', 'road_sign'}
MOD_OVERRIDE = {'bricks':'建材','decor_bench':'家具','doors':'门','double_flourecent_rod':'灯具','flags':'装饰','mattress':'家具','street_light_post':'灯具','floor_mirror':'建材','urban_fence_door':'门'}
TEX_OVERRIDE = {'beartrap':'装饰','bloodprops':'杂物','bricks':'建材','doors':'门','flags':'装饰','hatchback':'载具','lootcrates':'容器','mechanical':'其它','particle':'其它','particles':'其它','storefront':None}
ROOT_EXTRA = {'generator':'其它','guns':'其它','counter':'容器','framed':'屋顶','flourecent_rod':'灯具','corpse1':'装饰','tires':'装饰','wooden_pallet':'装饰','wood_particle':'其它','wire_item':'装饰','plastic_red':'家具','plastic_white':'家具','plastic_whitered':'家具','spruce_table':'家具','road_barrier':'装饰','road_barrier_big':'装饰','water_fountain':'市政设施','construction_barrier1':'路障','toilet2':'装饰','barbed_wire2':'装饰','folding_chair1':'家具','street_light_pole':'灯具','military_bed1':'家具','floor_mirror_black':'建材','gutter_inner':'装饰','broken_glass1':'装饰','traffic_cone1':'装饰','woodentable':'家具'}
def auto_cat(name):
v = collections.Counter()
for b, c in bid2cat.items():
if name == b or b.startswith(name+'_') or name.startswith(b+'_') or name.endswith('_'+b) or b.endswith('_'+name):
v[c] += 1
if not v: return None
top = max(v.values())
for c in CAT_ORDER:
if v.get(c,0) == top: return c
return None
def split_rule(f, b):
b = b.lower()
if f=='asphalt': return '灯具' if 'light_asphalt' in b else '建材'
if f=='cinder_block': return '建材' if '_wall' in b else '装饰'
if f=='duct': return '门' if 'trapdoor' in b else '建材'
if f=='storefront': return '门' if ('door' in b or 'header' in b) else '建材'
if f=='construction_barrier': return '灯具' if 'no_lamp' in b else '路障'
if f=='metal_counter': return '容器' if 'wall' in b else '装饰'
if f=='road_sign': return '灯具' if 'traffic_light' in b else '标牌'
return None
def resolve(kind, folder, rel):
base = os.path.splitext(os.path.basename(rel))[0]
if folder == '(root)':
return auto_cat(base) or ROOT_EXTRA.get(base) or auto_cat(re.sub(r'\d+$','',base)) or '其它'
ov = MOD_OVERRIDE if kind=='model' else TEX_OVERRIDE
if folder in ov and ov[folder]: return ov[folder]
if folder in SPLIT or (kind=='texture' and folder=='storefront'):
c = split_rule(folder, base)
if c: return c
return auto_cat(folder) or '其它'
z = zipfile.ZipFile(JAR)
names = z.namelist()
tex = [x.split('textures/block/',1)[1] for x in names if x.startswith('assets/sa_decor/textures/block/') and x.endswith('.png')]
mod = [x.split('models/block/',1)[1] for x in names if x.startswith('assets/sa_decor/models/block/') and x.endswith('.json')]
texset = set(tex); modset = set(mod)
tex_own = {}
for rel in tex:
f = rel.split('/')[0] if '/' in rel else '(root)'
tex_own[rel] = resolve('texture', f, rel)
REF = re.compile(r'sa_decor:(block|item)/([A-Za-z0-9_/.\-]+)')
no_ns = 0; with_ns = 0
cross = collections.Counter(); missing = collections.Counter()
ref_mod = 0
tex_ref_by_cat = collections.defaultdict(set)
for rel in mod:
f = rel.split('/')[0] if '/' in rel else '(root)'
mcat = resolve('model', f, rel)
txt = z.read('assets/sa_decor/models/block/'+rel).decode('utf-8', 'ignore')
if '"block/' in txt.replace('sa_decor:block/',''): no_ns += 1
for typ, p in REF.findall(txt):
with_ns += 1
if typ != 'block': continue
t = p + '.png'
if t in texset:
tc = tex_own[t]
tex_ref_by_cat[mcat].add(t)
if tc != mcat: cross[(mcat, tc)] += 1
elif p + '.json' in modset:
ref_mod += 1
else:
missing[p] += 1
print('模型总数', len(mod))
print('引用出现次数', with_ns, ' cite: 含无命名空间"block/"的模型数', no_ns)
print('引用到模型(parent等)次数', ref_mod)
print('=== 跨分类贴图引用 (模型分类 -> 贴图所在分类): 次数 ===')
for k, v in cross.most_common(30): print(' ', k, v)
print('跨分类总数:', sum(cross.values()))
print('=== 找不到的引用 (前30) ===')
for k, v in missing.most_common(30): print(' ', k, v)
print('缺失总数:', sum(missing.values()))
# 每个分类模型引用的贴图数(用于评估复制量)
print('=== 各分类模型引用贴图去重数 ===')
for c in CAT_ORDER:
if tex_ref_by_cat.get(c): print(' ', c, len(tex_ref_by_cat[c]))
+107
View File
@@ -0,0 +1,107 @@
# -*- coding: utf-8 -*-
"""生成《幸存者军火库-装饰方块分类表》md + xlsx"""
import json, os, collections
ROOT = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02'
RES = os.path.join(ROOT, '_sa_hanhua_out', '_tmp', 'decor_archive_result.json')
MD = os.path.join(ROOT, '\u5e78\u5b58\u8005\u519b\u706b\u5e93-\u88c5\u9970\u65b9\u5757\u5206\u7c7b\u8868.md')
XLSX = os.path.join(ROOT, '\u5e78\u5b58\u8005\u519b\u706b\u5e93-\u88c5\u9970\u65b9\u5757\u5206\u7c7b\u8868.xlsx')
CAT_ORDER = ['围栏', '家具', '容器', '屋顶', '市政设施', '建材', '杂物', '标牌', '灯具', '装饰', '路障', '载具', '门', '其它']
d = json.load(open(RES, encoding='utf-8'))
rows = [tuple(x) for x in d['rows']]
rec = {}
for k, v in d['rec'].items():
c, kind = k.split('|'); rec[(c, kind)] = v
folders = collections.defaultdict(dict)
for k, v in d['folders'].items():
kind, c, f = k.split('|', 2)
folders[(kind, c)][f] = v
block_cnt = collections.Counter(c for c, *_ in rows)
tex_tot = sum(v for (c, k), v in rec.items() if k == 'texture')
mod_tot = sum(v for (c, k), v in rec.items() if k == 'model')
out = []
out.append('# 幸存者军火库-装饰方块分类表\n')
out.append(f'> 范围:sa_decor 模组装饰方块,共 **{len(rows)}** 个。')
out.append(f'> 贴图 {tex_tot} 个 → `_sa_decor_textures/`;模型 {mod_tot} 个 → `_sa_decor_models/`。')
out.append('> 分类沿用《幸存者军火库-方块总表》的分类体系。\n')
out.append('## 一、分类汇总\n')
out.append('| 分类 | 方块数 | 贴图数 | 模型数 | 归档目录 |')
out.append('|---|---:|---:|---:|---|')
for c in CAT_ORDER:
if block_cnt.get(c, 0) == 0 and rec.get((c, 'texture'), 0) == 0 and rec.get((c, 'model'), 0) == 0:
continue
out.append(f'| {c} | {block_cnt.get(c,0)} | {rec.get((c,"texture"),0)} | {rec.get((c,"model"),0)} | `{c}` |')
out.append(f'| **合计** | **{len(rows)}** | **{tex_tot}** | **{mod_tot}** | |\n')
out.append('## 二、方块分类明细\n')
out.append('| 序号 | 分类 | 方块ID | 中文名 | 英文名 | 备注 |')
out.append('|---:|---|---|---|---|---|')
for i, (c, bid, en, zh, note) in enumerate(rows, 1):
out.append(f'| {i} | {c} | {bid} | {zh} | {en} | {note} |')
out.append('')
out.append('## 三、归档清单(每个分类下的贴图/模型分组)\n')
for c in CAT_ORDER:
tk = folders.get(('texture', c))
mk = folders.get(('model', c))
if not tk and not mk:
continue
out.append(f'### {c}\n')
for title, dd in (('贴图', tk), ('模型', mk)):
if not dd:
continue
out.append(f'**{title}**({sum(dd.values())} 个文件)\n')
out.append('| 分组文件夹 | 文件数 |')
out.append('|---|---:|')
for f in sorted(dd):
out.append(f'| `{f}` | {dd[f]} |')
out.append('')
md = '\n'.join(out)
open(MD, 'w', encoding='utf-8').write(md)
print('已写', MD)
# ---------- xlsx ----------
try:
from openpyxl import Workbook
from openpyxl.styles import Font
wb = Workbook()
ws = wb.active; ws.title = '分类汇总'
ws.append(['分类', '方块数', '贴图数', '模型数', '归档目录'])
for cell in ws[1]: cell.font = Font(bold=True)
for c in CAT_ORDER:
if block_cnt.get(c, 0) == 0 and rec.get((c, 'texture'), 0) == 0 and rec.get((c, 'model'), 0) == 0:
continue
ws.append([c, block_cnt.get(c, 0), rec.get((c, 'texture'), 0), rec.get((c, 'model'), 0), c])
ws.append(['合计', len(rows), tex_tot, mod_tot, ''])
for col, w in zip('ABCDE', (12, 10, 10, 10, 14)):
ws.column_dimensions[col].width = w
ws2 = wb.create_sheet('方块明细')
ws2.append(['序号', '分类', '方块ID', '中文名', '英文名', '备注'])
for cell in ws2[1]: cell.font = Font(bold=True)
for i, (c, bid, en, zh, note) in enumerate(rows, 1):
ws2.append([i, c, bid, zh, en, note])
for col, w in zip('ABCDEF', (6, 10, 30, 26, 30, 24)):
ws2.column_dimensions[col].width = w
ws3 = wb.create_sheet('归档清单')
ws3.append(['分类', '类型', '分组文件夹', '文件数'])
for cell in ws3[1]: cell.font = Font(bold=True)
for c in CAT_ORDER:
for kind, name in (('texture', '贴图'), ('model', '模型')):
dd = folders.get((kind, c))
if not dd: continue
for f in sorted(dd):
ws3.append([c, name, f, dd[f]])
for col, w in zip('ABCD', (10, 8, 34, 10)):
ws3.column_dimensions[col].width = w
wb.save(XLSX)
print('已写', XLSX)
except ImportError:
print('openpyxl 不可用,跳过 xlsx')
+30
View File
@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
import zipfile, json, os, sys, io
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
BASE = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02\_sa_hanhua_out'
JARS = ['sa_essentials-forge-1.20.1-1.0.0.jar', 'sa_lib-forge-1.20.1-1.0.1.jar', 'sa_decor-forge-1.20.1-1.0.3.jar']
OUT = os.path.join(BASE, '_tmp', 'herb_dump2')
os.makedirs(OUT, exist_ok=True)
KEY = 'herb'
for jn in JARS:
jp = os.path.join(BASE, jn)
if not os.path.exists(jp):
continue
z = zipfile.ZipFile(jp)
for n in z.namelist():
if KEY in n.lower() and not n.endswith('/'):
dest = os.path.join(OUT, jn.replace('.jar', ''), *n.split('/'))
os.makedirs(os.path.dirname(dest), exist_ok=True)
with open(dest, 'wb') as f:
f.write(z.read(n))
z.close()
print('dumped to', OUT)
for root, dirs, files in os.walk(OUT):
for f in files:
print(os.path.join(root, f))
@@ -0,0 +1,28 @@
import zipfile, os, json
base = r"e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02\_sa_hanhua_out"
p = os.path.join(base, "sa_essentials-forge-1.20.1-1.0.0.jar")
want_prefixes = [
"data/sa_combat/legendarysurvivaloverhaul/body_damage/consumables/",
"data/sa_combat/recipes/herbs/",
"data/sa_combat/loot_tables/blocks/",
"data/sa_combat/loot_modifiers/",
"data/sa_combat/tags/items/",
]
with zipfile.ZipFile(p) as z:
names = z.namelist()
for pre in want_prefixes:
print("#" * 30, pre)
for n in sorted(names):
if n.startswith(pre) and n.endswith('.json'):
if pre.endswith('blocks/') and 'herb' not in n:
continue
if pre.endswith('items/') and 'herb' not in n:
continue
try:
txt = z.read(n).decode('utf-8')
except Exception:
txt = "<decode error>"
print("-----", n)
print(txt.strip())
@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
import zipfile, json, os
root = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02\_sa_hanhua_out'
jar = os.path.join(root,'sa_essentials-forge-1.20.1-1.0.0.jar')
z = zipfile.ZipFile(jar)
names = z.namelist()
med = ['bandage','bandage_sterilized','plaster','splint','alcohol_wipes','blood_bag','blood_bag_empty',
'first_aid_kit','first_aid_kit_open','first_aid_spray','first_aid_spray_open','adrenaline',
'morphine','stim_shot','painkiller','painkiller_pills','stamina_boost','stamina_boost_pills','tube']
out=[]
for m in med:
p = 'assets/sa_combat/models/item/%s.json' % m
if p in names:
txt = z.read(p).decode('utf-8')
out.append('===== %s =====' % m)
out.append(txt[:1500])
else:
out.append('===== %s (NO MODEL JSON) =====' % m)
with open(os.path.join(root,'_tmp','medical_models.txt'),'w',encoding='utf-8') as f:
f.write('\n'.join(out))
print('done')
@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
import zipfile, os, struct
root = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02'
jar = os.path.join(root,'_sa_hanhua_out','sa_essentials-forge-1.20.1-1.0.0.jar')
outdir = os.path.join(root,'_sa_medical_textures')
os.makedirs(outdir, exist_ok=True)
ids = ['plaster','splint','alcohol_wipes','blood_bag','blood_bag_empty',
'painkiller_pills','stamina_boost_pills','tube']
z = zipfile.ZipFile(jar)
names = set(z.namelist())
report = []
def png_size(data):
# parse IHDR
if data[:8] != b'\x89PNG\r\n\x1a\n':
return None
w,h = struct.unpack('>II', data[16:24])
return (w,h)
for i in ids:
src = 'assets/sa_combat/textures/item/%s.png' % i
if src in names:
data = z.read(src)
with open(os.path.join(outdir, i+'.png'),'wb') as f:
f.write(data)
report.append('%s size=%s bytes=%d' % (i, png_size(data), len(data)))
else:
report.append('%s MISSING' % i)
# lang files
langs = [n for n in names if n.endswith('.json') and '/lang/' in n]
report.append('--- lang files ---')
report.append('\n'.join(langs))
for lf in langs:
try:
txt = z.read(lf).decode('utf-8', 'ignore')
except Exception as e:
continue
for i in ids:
for line in txt.splitlines():
low = line.lower()
if ('"%s"' % i) in low or ('.%s.' % i) in low or ('.%s"' % i) in low:
report.append('[%s] %s' % (os.path.basename(lf), line.strip()))
with open(os.path.join(root,'_sa_hanhua_out','_tmp','medical_tex.txt'),'w',encoding='utf-8') as f:
f.write('\n'.join(report))
print('done')
+38
View File
@@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
import os, re
targets = [
r'E:\mcsd\MCStudio',
r'E:\MCStudioDownload\game',
]
needles = ['缺少Manifest', 'Manifest配置', 'ManifestConfig', 'missing manifest', 'no manifest']
exts = ('.py', '.txt', '.json', '.lang', '.lua', '.js', '.xml', '.ini', '.cfg', '.md')
encs = ['utf-8', 'gbk', 'utf-16']
hits = []
for root in targets:
for dp, dn, fn in os.walk(root):
# skip heavy dirs
if any(s in dp.lower() for s in ('\\temp', '\\cache', '\\__pycache__')):
continue
for n in fn:
if not n.lower().endswith(exts):
continue
p = os.path.join(dp, n)
try:
if os.path.getsize(p) > 5_000_000:
continue
raw = open(p, 'rb').read()
except Exception:
continue
for enc in encs:
try:
t = raw.decode(enc)
except Exception:
continue
for nd in needles:
if nd in t:
hits.append('%s [%s] %s' % (p, enc, nd))
break
break
with open(r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02\_sa_hanhua_out\_tmp\grep_manifest.txt', 'w', encoding='utf-8') as f:
f.write('\n'.join(hits) if hits else 'NO HITS')
print('hits=%d' % len(hits))
@@ -0,0 +1,208 @@
# -*- coding: utf-8 -*-
"""生成《幸存者军火库 · 草药类物品属性表》(md + xlsx)
数据来源:sa_essentials-forge-1.20.1-1.0.0.jar (namespace sa_combat)
- SASurvivalItems.class 反汇编(效果/等级/时长/使用方式)
- data/sa_combat/recipes/herbs/*.json(合成配方)
- data/sa_combat/loot_tables/blocks/*_herb.json + loot_modifiers/hostile_herb_drops.json(获取方式)
- data/sa_combat/legendarysurvivaloverhaul/body_damage/consumables/*.json(LSO 身体治疗)
- assets/sa_combat/lang/zh_cn.json(中文名)
"""
import os
import io
import sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
ROOT = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\0aaaa4f2f16c46e8964025a5ab0ecc02'
# id, 中文名, 英文名, 类型, 使用方式, 使用时长, 药水效果, 解毒, LSO治疗, 配方, 获取方式
ROWS = [
# 生药草(ConsumableHerbBlockItem:可放置方块 + 可咀嚼食用,时长 60t)
("green_herb", "绿色药草", "Green Herb", "生药草(方块)", "咀嚼食用(EAT)/ 可放置", "60t / 3.0s",
"再生 I · 60t(3s)", "否", "1次 / 160t(8s) / 治疗 1.5 / 无附加恢复效果",
"—(不可合成)", "野采药草方块掉落自身 / 敌对生物被玩家击杀掉落 / 可种植"),
("red_herb", "红色药草", "Red Herb", "生药草(方块)", "咀嚼食用(EAT)/ 可放置", "60t / 3.0s",
"饱和 I · 40t(2s)", "否", "—",
"—(不可合成)", "野采药草方块掉落自身 / 敌对生物被玩家击杀掉落 / 可种植"),
("blue_herb", "蓝色药草", "Blue Herb", "生药草(方块)", "咀嚼食用(EAT)/ 可放置", "60t / 3.0s",
"再生 I · 40t(2s)", "否", "—",
"—(不可合成)", "野采药草方块掉落自身 / 敌对生物被玩家击杀掉落 / 可种植"),
("yellow_herb", "黄色药草", "Yellow Herb", "生药草(方块)", "咀嚼食用(EAT)/ 可放置", "60t / 3.0s",
"吸收 I · 100t(5s)", "否", "—",
"—(不可合成)", "野采药草方块掉落自身 / 敌对生物被玩家击杀掉落 / 可种植"),
# 捣碎药草(ConsumableEffectItem:食用 EAT,默认 32t)
("crushed_green_herb", "捣碎的绿色药草", "Crushed Green Herb", "捣碎药草", "食用(EAT)", "32t / 1.6s",
"再生 I · 100t(5s)", "否", "1次 / 140t(7s) / 治疗 1.5 / 无附加恢复效果",
"研钵 + 绿色药草", "合成"),
("crushed_red_herb", "捣碎的红色药草", "Crushed Red Herb", "捣碎药草", "食用(EAT)", "32t / 1.6s",
"饱和 I · 60t(3s)", "否", "—",
"研钵 + 红色药草", "合成"),
("crushed_blue_herb", "捣碎的蓝色药草", "Crushed Blue Herb", "捣碎药草", "食用(EAT)", "32t / 1.6s",
"—(仅解毒)", "是", "—",
"研钵 + 蓝色药草", "合成"),
("crushed_yellow_herb", "捣碎的黄色药草", "Crushed Yellow Herb", "捣碎药草", "食用(EAT)", "32t / 1.6s",
"吸收 I · 200t(10s)", "否", "—",
"研钵 + 黄色药草", "合成"),
# 混合草药(ConsumableEffectItem + UseAnim.DRINK,默认 32t)
("mixed_gg_herbs", "混合草药(绿+绿)", "Mixed GG Herbs", "混合草药", "饮用(DRINK)", "32t / 1.6s",
"再生 I · 160t(8s)", "否", "2次 / 180t(9s) / 治疗 3.0 / 恢复 I 80t(4s)",
"管子 + 捣碎的绿色药草 ×2", "合成"),
("mixed_ggg_herbs", "混合草药(绿+绿+绿)", "Mixed GGG Herbs", "混合草药", "饮用(DRINK)", "32t / 1.6s",
"再生 I · 300t(15s)", "否", "3次 / 220t(11s) / 治疗 4.5 / 恢复 I 120t(6s)",
"管子 + 捣碎的绿色药草 ×3;或 混合草药GG + 捣碎的绿色药草", "合成"),
("mixed_gr_herbs", "混合草药(绿+红)", "Mixed GR Herbs", "混合草药", "饮用(DRINK)", "32t / 1.6s",
"再生 I · 240t(12s)", "否", "3次 / 220t(11s) / 治疗 5.0 / 恢复 I 120t(6s)",
"管子 + 捣碎的绿色药草 + 捣碎的红色药草", "合成"),
("mixed_ggr_herbs", "混合草药(绿+绿+红)", "Mixed GGR Herbs", "混合草药", "饮用(DRINK)", "32t / 1.6s",
"再生 II · 240t(12s)", "否", "4次 / 260t(13s) / 治疗 6.0 / 恢复 II 160t(8s)",
"管子 + 捣碎的绿色药草 ×2 + 捣碎的红色药草;或 混合草药GG + 捣碎的红色药草;或 混合草药GR + 捣碎的绿色药草", "合成"),
("mixed_gb_herbs", "混合草药(绿+蓝)", "Mixed GB Herbs", "混合草药", "饮用(DRINK)", "32t / 1.6s",
"再生 I · 160t(8s)", "是", "2次 / 180t(9s) / 治疗 3.0 / 恢复 I 80t(4s)",
"管子 + 捣碎的绿色药草 + 捣碎的蓝色药草", "合成"),
("mixed_ggb_herbs", "混合草药(绿+绿+蓝)", "Mixed GGB Herbs", "混合草药", "饮用(DRINK)", "32t / 1.6s",
"再生 I · 200t(10s)", "是", "3次 / 220t(11s) / 治疗 4.0 / 恢复 I 120t(6s)",
"管子 + 捣碎的绿色药草 ×2 + 捣碎的蓝色药草;或 混合草药GB + 捣碎的绿色药草;或 混合草药GG + 捣碎的蓝色药草", "合成"),
("mixed_gy_herbs", "混合草药(绿+黄)", "Mixed GY Herbs", "混合草药", "饮用(DRINK)", "32t / 1.6s",
"再生 I · 160t(8s) + 吸收 I · 200t(10s)", "否", "2次 / 180t(9s) / 治疗 3.0 / 恢复 I 100t(5s)",
"管子 + 捣碎的绿色药草 + 捣碎的黄色药草", "合成"),
("mixed_ggy_herbs", "混合草药(绿+绿+黄)", "Mixed GGY Herbs", "混合草药", "饮用(DRINK)", "32t / 1.6s",
"再生 I · 240t(12s) + 吸收 I · 200t(10s)", "否", "3次 / 240t(12s) / 治疗 4.5 / 恢复 I 160t(8s)",
"管子 + 捣碎的绿色药草 ×2 + 捣碎的黄色药草;或 混合草药GG + 捣碎的黄色药草;或 混合草药GY + 捣碎的绿色药草", "合成"),
("mixed_gyb_herbs", "混合草药(绿+黄+蓝)", "Mixed GYB Herbs", "混合草药", "饮用(DRINK)", "32t / 1.6s",
"再生 I · 160t(8s) + 吸收 I · 200t(10s)", "是", "3次 / 220t(11s) / 治疗 4.0 / 恢复 I 120t(6s)",
"管子 + 捣碎的绿色药草 + 捣碎的黄色药草 + 捣碎的蓝色药草;或 混合草药GB + 捣碎的黄色药草;或 混合草药GY + 捣碎的蓝色药草", "合成"),
("mixed_gry_herbs", "混合草药(绿+红+黄)", "Mixed GRY Herbs", "混合草药", "饮用(DRINK)", "32t / 1.6s",
"再生 I · 240t(12s) + 吸收 II · 400t(20s)", "否", "4次 / 280t(14s) / 治疗 6.5 / 恢复 II 180t(9s)",
"管子 + 捣碎的绿色药草 + 捣碎的红色药草 + 捣碎的黄色药草;或 混合草药GR + 捣碎的黄色药草;或 混合草药GY + 捣碎的红色药草", "合成"),
("mixed_grb_herbs", "混合草药(绿+红+蓝)", "Mixed GRB Herbs", "混合草药", "饮用(DRINK)", "32t / 1.6s",
"再生 I · 240t(12s) + 吸收 I · 160t(8s)", "是", "4次 / 260t(13s) / 治疗 5.5 / 恢复 II 160t(8s)",
"管子 + 捣碎的绿色药草 + 捣碎的红色药草 + 捣碎的蓝色药草;或 混合草药GB + 捣碎的红色药草;或 混合草药GR + 捣碎的蓝色药草", "合成"),
("mixed_rb_herbs", "混合草药(红+蓝)", "Mixed RB Herbs", "混合草药", "饮用(DRINK)", "32t / 1.6s",
"再生 I · 100t(5s)", "是", "2次 / 180t(9s) / 治疗 2.5 / 恢复 I 80t(4s)",
"管子 + 捣碎的红色药草 + 捣碎的蓝色药草", "合成"),
]
HEADER = ["序号", "物品ID", "中文名", "英文名", "类型", "使用方式", "使用时长",
"药水效果(等级 / 时长)", "解毒", "LSO 身体治疗(次数 / 耗时 / 治疗值 / 恢复效果)",
"合成配方", "获取方式"]
rows = []
for i, r in enumerate(ROWS, 1):
rows.append([i] + list(r))
# ---------------- Markdown ----------------
md = []
md.append("# 幸存者军火库 · 草药类物品属性表")
md.append("")
md.append("来源:`sa_essentials-forge-1.20.1-1.0.0.jar`(命名空间 `sa_combat`),数据取自 `SASurvivalItems` 类反汇编 + `recipes/herbs/*.json` + `loot_tables` / `loot_modifiers` + LSO `body_damage/consumables/*.json` + `zh_cn.json`。")
md.append("")
md.append("单位换算:**t = tick,20t = 1 秒**;效果「I / II」对应 amplifier 0 / 1。")
md.append("")
md.append("| " + " | ".join(HEADER) + " |")
md.append("| " + " | ".join(["---"] * len(HEADER)) + " |")
for r in rows:
md.append("| " + " | ".join(str(x) for x in r) + " |")
md.append("")
md.append("---")
md.append("")
md.append("## 说明")
md.append("")
md.append("### 1. 三类草药的区别")
md.append("")
md.append("- **生药草**(绿色 / 红色 / 蓝色 / 黄色药草):`ConsumableHerbBlockItem` —— 既是**方块**(可放置、可种植、可破坏回收),也是**可咀嚼食用的物品**,咀嚼耗时 60t(3 秒),使用动画为 EAT。")
md.append("- **捣碎药草**(`crushed_*_herb`):`ConsumableEffectItem` —— 仅可食用,使用动画 EAT,耗时 32t(1.6 秒)。")
md.append("- **混合草药**(`mixed_*_herbs`):`ConsumableEffectItem` —— 使用动画为 **DRINK(饮用)**,耗时 32t(1.6 秒)。")
md.append("")
md.append("### 2. 药水效果")
md.append("")
md.append("| 效果 | 说明 |")
md.append("| --- | --- |")
md.append("| 再生 I / II | Regeneration,amplifier 0 / 1 |")
md.append("| 饱和 I | Saturation |")
md.append("| 吸收 I / II | Absorption,+2 点/级 额外生命 |")
md.append("")
md.append("- **解毒** = 使用后移除玩家身上的**中毒**效果(`LivingEntity.removeEffect(POISON)`),与药水效果独立结算。")
md.append("")
md.append("### 3. LSO 身体治疗(依赖 Legendary Survival Overhaul)")
md.append("")
md.append("- `次数` = healing_charges(分几次缓慢治疗);`耗时` = healing_time(每次治疗持续时间,tick);`治疗值` = healing_value(每次恢复的身体部位 HP);`恢复效果` = recovery_effect(治疗结束后附加的增益,amplifier / duration)。")
md.append("- **仅有 14 个草药带 LSO 数据**:绿色药草、捣碎的绿色药草,以及 12 个混合草药。")
md.append("- **红色 / 蓝色 / 黄色药草、捣碎的红色 / 蓝色 / 黄色药草共 6 个没有 LSO 治疗数据**。")
md.append("")
md.append("### 4. 获取方式")
md.append("")
md.append("- **生药草的 4 个方块**破坏后 100% 掉落自身(`survives_explosion`,不受爆炸影响)。")
md.append("- **敌对生物掉落**:由 `hostile_herb_drops` 掉落修正器控制 —— 仅对 `Enemy`(敌对生物)生效,且必须是**被玩家击杀**;先按 `HOSTILE_HERB_DROP_CHANCE` 判定是否掉落,命中后按权重随机:")
md.append("")
md.append("| 随机值区间 | 掉落物 |")
md.append("| --- | --- |")
md.append("| < 0.55 | 绿色药草 |")
md.append("| 0.55 ~ 0.80 | 蓝色药草 |")
md.append("| 0.80 ~ 0.95 | 黄色药草 |")
md.append("| ≥ 0.95 | 红色药草 |")
md.append("")
md.append("- **捣碎药草**:`研钵`(sa_core:mortar_and_pestle) + 对应生药草,无序合成。")
md.append("- **混合草药**:`管子`(sa_combat:tube) + 2~3 个捣碎药草,无序合成;部分混合草药还支持「已混合草药 + 捣碎药草」的两材料追加配方。")
md.append("")
md.append("### 5. 命名说明")
md.append("")
md.append("- 本表中文名以 `sa_essentials` jar 内 `assets/sa_combat/lang/zh_cn.json` 为准。")
md.append("- 旧《幸存者军火库食物表》中的简称(绿草 / 红草 / 蓝草 / 黄草 / 绿草粉 / 红草粉…)与本表为同物异名,请以本表为准。")
md.append("- 注:以上草药均为 Java 模组内容,**当前尚未导入基岩版行为包 / 资源包**。")
md.append("")
md_path = os.path.join(ROOT, '幸存者军火库-草药属性表.md')
with open(md_path, 'w', encoding='utf-8') as f:
f.write("\n".join(md))
print('written', md_path)
# ---------------- Excel ----------------
try:
from openpyxl import Workbook
from openpyxl.styles import Font, PatternFill, Alignment, Border, Side
from openpyxl.utils import get_column_letter
wb = Workbook()
ws = wb.active
ws.title = "草药类物品属性"
title = "幸存者军火库 · 草药类物品属性表(Java 模组 sa_combat)"
ws.append([title])
ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=len(HEADER))
ws.cell(row=1, column=1).font = Font(bold=True, size=13)
ws.cell(row=1, column=1).alignment = Alignment(horizontal='center', vertical='center')
ws.row_dimensions[1].height = 26
ws.append(HEADER)
for c in range(1, len(HEADER) + 1):
cell = ws.cell(row=2, column=c)
cell.font = Font(bold=True, color='FFFFFF')
cell.fill = PatternFill('solid', fgColor='4472C4')
cell.alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
ws.row_dimensions[2].height = 34
for r in rows:
ws.append(r)
thin = Side(style='thin', color='B0B0B0')
border = Border(left=thin, right=thin, top=thin, bottom=thin)
for row in ws.iter_rows(min_row=2, max_row=2 + len(rows), max_col=len(HEADER)):
for cell in row:
cell.border = border
cell.alignment = Alignment(vertical='center', wrap_text=True)
for row in ws.iter_rows(min_row=3, max_row=2 + len(rows), min_col=1, max_col=2):
for cell in row:
cell.alignment = Alignment(horizontal='center', vertical='center', wrap_text=True)
widths = [5, 22, 20, 20, 14, 22, 12, 34, 6, 40, 60, 40]
for i, w in enumerate(widths, 1):
ws.column_dimensions[get_column_letter(i)].width = w
ws.freeze_panes = 'C3'
xlsx_path = os.path.join(ROOT, '幸存者军火库-草药属性表.xlsx')
wb.save(xlsx_path)
print('written', xlsx_path)
except ImportError as e:
print('openpyxl not available:', e)
@@ -0,0 +1,52 @@
{
"values": [
{
"id": "sa_combat:green_herb",
"required": false
},
{
"id": "sa_combat:red_herb",
"required": false
},
{
"id": "sa_combat:blue_herb",
"required": false
},
{
"id": "sa_combat:yellow_herb",
"required": false
},
{
"id": "sa_combat:crushed_green_herb",
"required": false
},
{
"id": "sa_combat:crushed_red_herb",
"required": false
},
{
"id": "sa_combat:crushed_blue_herb",
"required": false
},
{
"id": "sa_combat:crushed_yellow_herb",
"required": false
},
{
"id": "sa_combat:mixed_gg_herbs",
"required": false
},
{
"id": "sa_combat:mixed_gr_herbs",
"required": false
},
{
"id": "sa_combat:mixed_gb_herbs",
"required": false
},
{
"id": "sa_combat:mixed_gy_herbs",
"required": false
}
]
}
@@ -0,0 +1,19 @@
{
"variants": {
"facing=east": {
"model": "sa_combat:block/blue_herb",
"y": 90
},
"facing=north": {
"model": "sa_combat:block/blue_herb"
},
"facing=south": {
"model": "sa_combat:block/blue_herb",
"y": 180
},
"facing=west": {
"model": "sa_combat:block/blue_herb",
"y": 270
}
}
}
@@ -0,0 +1,19 @@
{
"variants": {
"facing=east": {
"model": "sa_combat:block/green_herb",
"y": 90
},
"facing=north": {
"model": "sa_combat:block/green_herb"
},
"facing=south": {
"model": "sa_combat:block/green_herb",
"y": 180
},
"facing=west": {
"model": "sa_combat:block/green_herb",
"y": 270
}
}
}
@@ -0,0 +1,19 @@
{
"variants": {
"facing=east": {
"model": "sa_combat:block/red_herb",
"y": 90
},
"facing=north": {
"model": "sa_combat:block/red_herb"
},
"facing=south": {
"model": "sa_combat:block/red_herb",
"y": 180
},
"facing=west": {
"model": "sa_combat:block/red_herb",
"y": 270
}
}
}
@@ -0,0 +1,19 @@
{
"variants": {
"facing=east": {
"model": "sa_combat:block/yellow_herb",
"y": 90
},
"facing=north": {
"model": "sa_combat:block/yellow_herb"
},
"facing=south": {
"model": "sa_combat:block/yellow_herb",
"y": 180
},
"facing=west": {
"model": "sa_combat:block/yellow_herb",
"y": 270
}
}
}
@@ -0,0 +1,231 @@
{
"format_version": "1.21.11",
"credit": "Made with Blockbench",
"render_type": "cutout_mipped",
"texture_size": [32, 32],
"textures": {
"3": "sa_combat:block/blue_herb",
"particle": "sa_combat:block/blue_herb"
},
"elements": [
{
"from": [5, 0, 5],
"to": [11, 5, 11],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7]},
"faces": {
"north": {"uv": [7, 8.5, 10, 11], "texture": "#3"},
"east": {"uv": [4, 7, 7, 9.5], "texture": "#3"},
"south": {"uv": [7, 6, 10, 8.5], "texture": "#3"},
"west": {"uv": [0, 8, 3, 10.5], "texture": "#3"},
"up": {"uv": [10, 3, 7, 0], "rotation": 90, "texture": "#3"},
"down": {"uv": [10, 3, 7, 6], "rotation": 270, "texture": "#3"}
}
},
{
"from": [4, 5, 4],
"to": [12, 7, 12],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 5, 7]},
"faces": {
"north": {"uv": [10, 0, 14, 1], "texture": "#3"},
"east": {"uv": [10, 1, 14, 2], "texture": "#3"},
"south": {"uv": [10, 2, 14, 3], "texture": "#3"},
"west": {"uv": [10, 3, 14, 4], "texture": "#3"},
"up": {"uv": [4, 4, 0, 0], "texture": "#3"},
"down": {"uv": [4, 4, 0, 8], "texture": "#3"}
}
},
{
"from": [8, 7, 7],
"to": [8, 17, 9],
"rotation": {"angle": 0, "axis": "y", "origin": [7, 7, 7]},
"faces": {
"north": {"uv": [0, 0, 0, 5], "texture": "#3"},
"east": {"uv": [5, 9.5, 4, 14.5], "texture": "#3"},
"south": {"uv": [0, 0, 0, 5], "texture": "#3"},
"west": {"uv": [4, 9.5, 5, 14.5], "texture": "#3"},
"up": {"uv": [0, 1, 0, 0], "texture": "#3"},
"down": {"uv": [0, 0, 0, 1], "texture": "#3"}
}
},
{
"from": [7, 7, 8],
"to": [9, 17, 8],
"rotation": {"angle": 0, "axis": "y", "origin": [9, 7, 7]},
"faces": {
"north": {"uv": [4, 9.5, 5, 14.5], "texture": "#3"},
"east": {"uv": [0, 0, 0, 5], "texture": "#3"},
"south": {"uv": [5, 9.5, 4, 14.5], "texture": "#3"},
"west": {"uv": [0, 0, 0, 5], "texture": "#3"},
"up": {"uv": [0, 1, 0, 0], "rotation": 90, "texture": "#3"},
"down": {"uv": [0, 0, 0, 1], "rotation": 270, "texture": "#3"}
}
},
{
"from": [0.5, 14, 5.5],
"to": [7.5, 14, 10.5],
"rotation": {"angle": 22.5, "axis": "z", "origin": [7.5, 13, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"east": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [0.5, 10, 5.5],
"to": [7.5, 10, 10.5],
"rotation": {"angle": 22.5, "axis": "z", "origin": [7.5, 9, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"east": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [8.5, 14, 5.5],
"to": [15.5, 14, 10.5],
"rotation": {"angle": -22.5, "axis": "z", "origin": [8.5, 13, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"west": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"up": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"},
"down": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [8.5, 10, 5.5],
"to": [15.5, 10, 10.5],
"rotation": {"angle": -22.5, "axis": "z", "origin": [8.5, 9, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"west": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"up": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"},
"down": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [5.5, 13, 1],
"to": [10.5, 13, 8],
"rotation": {"angle": -22.5, "axis": "x", "origin": [8, 12, 1]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 8.5, 14.5, 5], "texture": "#3"},
"down": {"uv": [12, 8.5, 14.5, 5], "rotation": 180, "texture": "#3"}
}
},
{
"from": [5.5, 9, 1],
"to": [10.5, 9, 8],
"rotation": {"angle": -22.5, "axis": "x", "origin": [8, 8, 1]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 8.5, 14.5, 5], "texture": "#3"},
"down": {"uv": [12, 8.5, 14.5, 5], "rotation": 180, "texture": "#3"}
}
},
{
"from": [5.5, 12, 8],
"to": [10.5, 12, 15],
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 11, 15]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 3.5, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 3.5, 0, 0], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 180, "texture": "#3"}
}
},
{
"from": [5.5, 8, 8],
"to": [10.5, 8, 15],
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 7, 15]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 3.5, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 3.5, 0, 0], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 180, "texture": "#3"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [75, 45, 0],
"translation": [0, 2, 1.75],
"scale": [0.46289, 0.46289, 0.46289]
},
"thirdperson_lefthand": {
"rotation": [75, 45, 0],
"translation": [0, 2, 1.75],
"scale": [0.46289, 0.46289, 0.46289]
},
"firstperson_righthand": {
"translation": [1.25, 2.5, 0],
"scale": [0.53516, 0.53516, 0.53516]
},
"firstperson_lefthand": {
"translation": [1.25, 2.5, 0],
"scale": [0.53516, 0.53516, 0.53516]
},
"gui": {
"rotation": [30, -135, 0],
"scale": [0.85352, 0.85352, 0.85352]
}
},
"groups": [
{
"name": "group",
"origin": [7, 11, 7],
"scope": 0,
"color": 0,
"children": [0, 1]
},
2,
3,
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [4, 5]
},
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [6, 7]
},
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [8, 9]
},
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [10, 11]
}
]
}
@@ -0,0 +1,231 @@
{
"format_version": "1.21.11",
"credit": "Made with Blockbench",
"render_type": "cutout_mipped",
"texture_size": [32, 32],
"textures": {
"3": "sa_combat:block/green_herb",
"particle": "sa_combat:block/green_herb"
},
"elements": [
{
"from": [5, 0, 5],
"to": [11, 5, 11],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7]},
"faces": {
"north": {"uv": [7, 8.5, 10, 11], "texture": "#3"},
"east": {"uv": [4, 7, 7, 9.5], "texture": "#3"},
"south": {"uv": [7, 6, 10, 8.5], "texture": "#3"},
"west": {"uv": [0, 8, 3, 10.5], "texture": "#3"},
"up": {"uv": [10, 3, 7, 0], "rotation": 90, "texture": "#3"},
"down": {"uv": [10, 3, 7, 6], "rotation": 270, "texture": "#3"}
}
},
{
"from": [4, 5, 4],
"to": [12, 7, 12],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 5, 7]},
"faces": {
"north": {"uv": [10, 0, 14, 1], "texture": "#3"},
"east": {"uv": [10, 1, 14, 2], "texture": "#3"},
"south": {"uv": [10, 2, 14, 3], "texture": "#3"},
"west": {"uv": [10, 3, 14, 4], "texture": "#3"},
"up": {"uv": [4, 4, 0, 0], "texture": "#3"},
"down": {"uv": [4, 4, 0, 8], "texture": "#3"}
}
},
{
"from": [8, 7, 7],
"to": [8, 17, 9],
"rotation": {"angle": 0, "axis": "y", "origin": [7, 7, 7]},
"faces": {
"north": {"uv": [0, 0, 0, 5], "texture": "#3"},
"east": {"uv": [5, 9.5, 4, 14.5], "texture": "#3"},
"south": {"uv": [0, 0, 0, 5], "texture": "#3"},
"west": {"uv": [4, 9.5, 5, 14.5], "texture": "#3"},
"up": {"uv": [0, 1, 0, 0], "texture": "#3"},
"down": {"uv": [0, 0, 0, 1], "texture": "#3"}
}
},
{
"from": [7, 7, 8],
"to": [9, 17, 8],
"rotation": {"angle": 0, "axis": "y", "origin": [9, 7, 7]},
"faces": {
"north": {"uv": [4, 9.5, 5, 14.5], "texture": "#3"},
"east": {"uv": [0, 0, 0, 5], "texture": "#3"},
"south": {"uv": [5, 9.5, 4, 14.5], "texture": "#3"},
"west": {"uv": [0, 0, 0, 5], "texture": "#3"},
"up": {"uv": [0, 1, 0, 0], "rotation": 90, "texture": "#3"},
"down": {"uv": [0, 0, 0, 1], "rotation": 270, "texture": "#3"}
}
},
{
"from": [0.5, 14, 5.5],
"to": [7.5, 14, 10.5],
"rotation": {"angle": 22.5, "axis": "z", "origin": [7.5, 13, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"east": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [0.5, 10, 5.5],
"to": [7.5, 10, 10.5],
"rotation": {"angle": 22.5, "axis": "z", "origin": [7.5, 9, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"east": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [8.5, 14, 5.5],
"to": [15.5, 14, 10.5],
"rotation": {"angle": -22.5, "axis": "z", "origin": [8.5, 13, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"west": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"up": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"},
"down": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [8.5, 10, 5.5],
"to": [15.5, 10, 10.5],
"rotation": {"angle": -22.5, "axis": "z", "origin": [8.5, 9, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"west": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"up": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"},
"down": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [5.5, 13, 1],
"to": [10.5, 13, 8],
"rotation": {"angle": -22.5, "axis": "x", "origin": [8, 12, 1]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 8.5, 14.5, 5], "texture": "#3"},
"down": {"uv": [12, 8.5, 14.5, 5], "rotation": 180, "texture": "#3"}
}
},
{
"from": [5.5, 9, 1],
"to": [10.5, 9, 8],
"rotation": {"angle": -22.5, "axis": "x", "origin": [8, 8, 1]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 8.5, 14.5, 5], "texture": "#3"},
"down": {"uv": [12, 8.5, 14.5, 5], "rotation": 180, "texture": "#3"}
}
},
{
"from": [5.5, 12, 8],
"to": [10.5, 12, 15],
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 11, 15]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 3.5, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 3.5, 0, 0], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 180, "texture": "#3"}
}
},
{
"from": [5.5, 8, 8],
"to": [10.5, 8, 15],
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 7, 15]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 3.5, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 3.5, 0, 0], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 180, "texture": "#3"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [75, 45, 0],
"translation": [0, 2, 1.75],
"scale": [0.46289, 0.46289, 0.46289]
},
"thirdperson_lefthand": {
"rotation": [75, 45, 0],
"translation": [0, 2, 1.75],
"scale": [0.46289, 0.46289, 0.46289]
},
"firstperson_righthand": {
"translation": [1.25, 2.5, 0],
"scale": [0.53516, 0.53516, 0.53516]
},
"firstperson_lefthand": {
"translation": [1.25, 2.5, 0],
"scale": [0.53516, 0.53516, 0.53516]
},
"gui": {
"rotation": [30, -135, 0],
"scale": [0.85352, 0.85352, 0.85352]
}
},
"groups": [
{
"name": "group",
"origin": [7, 11, 7],
"scope": 0,
"color": 0,
"children": [0, 1]
},
2,
3,
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [4, 5]
},
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [6, 7]
},
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [8, 9]
},
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [10, 11]
}
]
}
@@ -0,0 +1,231 @@
{
"format_version": "1.21.11",
"credit": "Made with Blockbench",
"render_type": "cutout_mipped",
"texture_size": [32, 32],
"textures": {
"3": "sa_combat:block/red_herb",
"particle": "sa_combat:block/red_herb"
},
"elements": [
{
"from": [5, 0, 5],
"to": [11, 5, 11],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7]},
"faces": {
"north": {"uv": [7, 8.5, 10, 11], "texture": "#3"},
"east": {"uv": [4, 7, 7, 9.5], "texture": "#3"},
"south": {"uv": [7, 6, 10, 8.5], "texture": "#3"},
"west": {"uv": [0, 8, 3, 10.5], "texture": "#3"},
"up": {"uv": [10, 3, 7, 0], "rotation": 90, "texture": "#3"},
"down": {"uv": [10, 3, 7, 6], "rotation": 270, "texture": "#3"}
}
},
{
"from": [4, 5, 4],
"to": [12, 7, 12],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 5, 7]},
"faces": {
"north": {"uv": [10, 0, 14, 1], "texture": "#3"},
"east": {"uv": [10, 1, 14, 2], "texture": "#3"},
"south": {"uv": [10, 2, 14, 3], "texture": "#3"},
"west": {"uv": [10, 3, 14, 4], "texture": "#3"},
"up": {"uv": [4, 4, 0, 0], "texture": "#3"},
"down": {"uv": [4, 4, 0, 8], "texture": "#3"}
}
},
{
"from": [8, 7, 7],
"to": [8, 17, 9],
"rotation": {"angle": 0, "axis": "y", "origin": [7, 7, 7]},
"faces": {
"north": {"uv": [0, 0, 0, 5], "texture": "#3"},
"east": {"uv": [5, 9.5, 4, 14.5], "texture": "#3"},
"south": {"uv": [0, 0, 0, 5], "texture": "#3"},
"west": {"uv": [4, 9.5, 5, 14.5], "texture": "#3"},
"up": {"uv": [0, 1, 0, 0], "texture": "#3"},
"down": {"uv": [0, 0, 0, 1], "texture": "#3"}
}
},
{
"from": [7, 7, 8],
"to": [9, 17, 8],
"rotation": {"angle": 0, "axis": "y", "origin": [9, 7, 7]},
"faces": {
"north": {"uv": [4, 9.5, 5, 14.5], "texture": "#3"},
"east": {"uv": [0, 0, 0, 5], "texture": "#3"},
"south": {"uv": [5, 9.5, 4, 14.5], "texture": "#3"},
"west": {"uv": [0, 0, 0, 5], "texture": "#3"},
"up": {"uv": [0, 1, 0, 0], "rotation": 90, "texture": "#3"},
"down": {"uv": [0, 0, 0, 1], "rotation": 270, "texture": "#3"}
}
},
{
"from": [0.5, 14, 5.5],
"to": [7.5, 14, 10.5],
"rotation": {"angle": 22.5, "axis": "z", "origin": [7.5, 13, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"east": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [0.5, 10, 5.5],
"to": [7.5, 10, 10.5],
"rotation": {"angle": 22.5, "axis": "z", "origin": [7.5, 9, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"east": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [8.5, 14, 5.5],
"to": [15.5, 14, 10.5],
"rotation": {"angle": -22.5, "axis": "z", "origin": [8.5, 13, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"west": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"up": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"},
"down": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [8.5, 10, 5.5],
"to": [15.5, 10, 10.5],
"rotation": {"angle": -22.5, "axis": "z", "origin": [8.5, 9, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"west": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"up": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"},
"down": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [5.5, 13, 1],
"to": [10.5, 13, 8],
"rotation": {"angle": -22.5, "axis": "x", "origin": [8, 12, 1]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 8.5, 14.5, 5], "texture": "#3"},
"down": {"uv": [12, 8.5, 14.5, 5], "rotation": 180, "texture": "#3"}
}
},
{
"from": [5.5, 9, 1],
"to": [10.5, 9, 8],
"rotation": {"angle": -22.5, "axis": "x", "origin": [8, 8, 1]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 8.5, 14.5, 5], "texture": "#3"},
"down": {"uv": [12, 8.5, 14.5, 5], "rotation": 180, "texture": "#3"}
}
},
{
"from": [5.5, 12, 8],
"to": [10.5, 12, 15],
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 11, 15]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 3.5, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 3.5, 0, 0], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 180, "texture": "#3"}
}
},
{
"from": [5.5, 8, 8],
"to": [10.5, 8, 15],
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 7, 15]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 3.5, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 3.5, 0, 0], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 180, "texture": "#3"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [75, 45, 0],
"translation": [0, 2, 1.75],
"scale": [0.46289, 0.46289, 0.46289]
},
"thirdperson_lefthand": {
"rotation": [75, 45, 0],
"translation": [0, 2, 1.75],
"scale": [0.46289, 0.46289, 0.46289]
},
"firstperson_righthand": {
"translation": [1.25, 2.5, 0],
"scale": [0.53516, 0.53516, 0.53516]
},
"firstperson_lefthand": {
"translation": [1.25, 2.5, 0],
"scale": [0.53516, 0.53516, 0.53516]
},
"gui": {
"rotation": [30, -135, 0],
"scale": [0.85352, 0.85352, 0.85352]
}
},
"groups": [
{
"name": "group",
"origin": [7, 11, 7],
"scope": 0,
"color": 0,
"children": [0, 1]
},
2,
3,
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [4, 5]
},
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [6, 7]
},
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [8, 9]
},
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [10, 11]
}
]
}
@@ -0,0 +1,231 @@
{
"format_version": "1.21.11",
"credit": "Made with Blockbench",
"render_type": "cutout_mipped",
"texture_size": [32, 32],
"textures": {
"3": "sa_combat:block/yellow_herb",
"particle": "sa_combat:block/yellow_herb"
},
"elements": [
{
"from": [5, 0, 5],
"to": [11, 5, 11],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 0, 7]},
"faces": {
"north": {"uv": [7, 8.5, 10, 11], "texture": "#3"},
"east": {"uv": [4, 7, 7, 9.5], "texture": "#3"},
"south": {"uv": [7, 6, 10, 8.5], "texture": "#3"},
"west": {"uv": [0, 8, 3, 10.5], "texture": "#3"},
"up": {"uv": [10, 3, 7, 0], "rotation": 90, "texture": "#3"},
"down": {"uv": [10, 3, 7, 6], "rotation": 270, "texture": "#3"}
}
},
{
"from": [4, 5, 4],
"to": [12, 7, 12],
"rotation": {"angle": 0, "axis": "y", "origin": [8, 5, 7]},
"faces": {
"north": {"uv": [10, 0, 14, 1], "texture": "#3"},
"east": {"uv": [10, 1, 14, 2], "texture": "#3"},
"south": {"uv": [10, 2, 14, 3], "texture": "#3"},
"west": {"uv": [10, 3, 14, 4], "texture": "#3"},
"up": {"uv": [4, 4, 0, 0], "texture": "#3"},
"down": {"uv": [4, 4, 0, 8], "texture": "#3"}
}
},
{
"from": [8, 7, 7],
"to": [8, 17, 9],
"rotation": {"angle": 0, "axis": "y", "origin": [7, 7, 7]},
"faces": {
"north": {"uv": [0, 0, 0, 5], "texture": "#3"},
"east": {"uv": [5, 9.5, 4, 14.5], "texture": "#3"},
"south": {"uv": [0, 0, 0, 5], "texture": "#3"},
"west": {"uv": [4, 9.5, 5, 14.5], "texture": "#3"},
"up": {"uv": [0, 1, 0, 0], "texture": "#3"},
"down": {"uv": [0, 0, 0, 1], "texture": "#3"}
}
},
{
"from": [7, 7, 8],
"to": [9, 17, 8],
"rotation": {"angle": 0, "axis": "y", "origin": [9, 7, 7]},
"faces": {
"north": {"uv": [4, 9.5, 5, 14.5], "texture": "#3"},
"east": {"uv": [0, 0, 0, 5], "texture": "#3"},
"south": {"uv": [5, 9.5, 4, 14.5], "texture": "#3"},
"west": {"uv": [0, 0, 0, 5], "texture": "#3"},
"up": {"uv": [0, 1, 0, 0], "rotation": 90, "texture": "#3"},
"down": {"uv": [0, 0, 0, 1], "rotation": 270, "texture": "#3"}
}
},
{
"from": [0.5, 14, 5.5],
"to": [7.5, 14, 10.5],
"rotation": {"angle": 22.5, "axis": "z", "origin": [7.5, 13, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"east": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [0.5, 10, 5.5],
"to": [7.5, 10, 10.5],
"rotation": {"angle": 22.5, "axis": "z", "origin": [7.5, 9, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"east": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [8.5, 14, 5.5],
"to": [15.5, 14, 10.5],
"rotation": {"angle": -22.5, "axis": "z", "origin": [8.5, 13, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"west": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"up": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"},
"down": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [8.5, 10, 5.5],
"to": [15.5, 10, 10.5],
"rotation": {"angle": -22.5, "axis": "z", "origin": [8.5, 9, 8]},
"faces": {
"north": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"west": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"up": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"},
"down": {"uv": [14.5, 8.5, 12, 5], "rotation": 90, "texture": "#3"}
}
},
{
"from": [5.5, 13, 1],
"to": [10.5, 13, 8],
"rotation": {"angle": -22.5, "axis": "x", "origin": [8, 12, 1]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 8.5, 14.5, 5], "texture": "#3"},
"down": {"uv": [12, 8.5, 14.5, 5], "rotation": 180, "texture": "#3"}
}
},
{
"from": [5.5, 9, 1],
"to": [10.5, 9, 8],
"rotation": {"angle": -22.5, "axis": "x", "origin": [8, 8, 1]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 0, 0, 3.5], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 0, 0, 3.5], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 8.5, 14.5, 5], "texture": "#3"},
"down": {"uv": [12, 8.5, 14.5, 5], "rotation": 180, "texture": "#3"}
}
},
{
"from": [5.5, 12, 8],
"to": [10.5, 12, 15],
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 11, 15]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 3.5, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 3.5, 0, 0], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 180, "texture": "#3"}
}
},
{
"from": [5.5, 8, 8],
"to": [10.5, 8, 15],
"rotation": {"angle": 22.5, "axis": "x", "origin": [8, 7, 15]},
"faces": {
"north": {"uv": [0, 3, 0, 0], "rotation": 90, "texture": "#3"},
"east": {"uv": [0, 3.5, 0, 0], "rotation": 90, "texture": "#3"},
"south": {"uv": [0, 0, 0, 3], "rotation": 90, "texture": "#3"},
"west": {"uv": [0, 3.5, 0, 0], "rotation": 270, "texture": "#3"},
"up": {"uv": [12, 5, 14.5, 8.5], "texture": "#3"},
"down": {"uv": [12, 5, 14.5, 8.5], "rotation": 180, "texture": "#3"}
}
}
],
"display": {
"thirdperson_righthand": {
"rotation": [75, 45, 0],
"translation": [0, 2, 1.75],
"scale": [0.46289, 0.46289, 0.46289]
},
"thirdperson_lefthand": {
"rotation": [75, 45, 0],
"translation": [0, 2, 1.75],
"scale": [0.46289, 0.46289, 0.46289]
},
"firstperson_righthand": {
"translation": [1.25, 2.5, 0],
"scale": [0.53516, 0.53516, 0.53516]
},
"firstperson_lefthand": {
"translation": [1.25, 2.5, 0],
"scale": [0.53516, 0.53516, 0.53516]
},
"gui": {
"rotation": [30, -135, 0],
"scale": [0.85352, 0.85352, 0.85352]
}
},
"groups": [
{
"name": "group",
"origin": [7, 11, 7],
"scope": 0,
"color": 0,
"children": [0, 1]
},
2,
3,
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [4, 5]
},
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [6, 7]
},
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [8, 9]
},
{
"name": "group",
"origin": [7.5, 14, 8],
"scope": 0,
"color": 0,
"children": [10, 11]
}
]
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/blue_herb"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/crushed_blue_herb"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/crushed_green_herb"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/crushed_red_herb"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/crushed_yellow_herb"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/green_herb"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/mixed_gb_herbs"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/mixed_gg_herbs"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/mixed_ggb_herbs"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/mixed_ggg_herbs"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/mixed_ggr_herbs"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/mixed_ggy_herbs"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/mixed_gr_herbs"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/mixed_grb_herbs"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/mixed_gry_herbs"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/mixed_gy_herbs"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/mixed_gyb_herbs"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/mixed_rb_herbs"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/red_herb"
}
}
@@ -0,0 +1,6 @@
{
"parent": "minecraft:item/generated",
"textures": {
"layer0": "sa_combat:item/yellow_herb"
}
}
@@ -0,0 +1,7 @@
{
"healing_charges": 1,
"healing_time": 140,
"healing_value": 1.5,
"recovery_effect_amplifier": 0,
"recovery_effect_duration": 0
}
@@ -0,0 +1,7 @@
{
"healing_charges": 1,
"healing_time": 160,
"healing_value": 1.5,
"recovery_effect_amplifier": 0,
"recovery_effect_duration": 0
}
@@ -0,0 +1,7 @@
{
"healing_charges": 2,
"healing_time": 180,
"healing_value": 3.0,
"recovery_effect_amplifier": 0,
"recovery_effect_duration": 80
}
@@ -0,0 +1,7 @@
{
"healing_charges": 2,
"healing_time": 180,
"healing_value": 3.0,
"recovery_effect_amplifier": 0,
"recovery_effect_duration": 80
}
@@ -0,0 +1,7 @@
{
"healing_charges": 3,
"healing_time": 220,
"healing_value": 4.0,
"recovery_effect_amplifier": 0,
"recovery_effect_duration": 120
}
@@ -0,0 +1,7 @@
{
"healing_charges": 3,
"healing_time": 220,
"healing_value": 4.5,
"recovery_effect_amplifier": 0,
"recovery_effect_duration": 120
}
@@ -0,0 +1,7 @@
{
"healing_charges": 4,
"healing_time": 260,
"healing_value": 6.0,
"recovery_effect_amplifier": 1,
"recovery_effect_duration": 160
}
@@ -0,0 +1,7 @@
{
"healing_charges": 3,
"healing_time": 240,
"healing_value": 4.5,
"recovery_effect_amplifier": 0,
"recovery_effect_duration": 160
}
@@ -0,0 +1,7 @@
{
"healing_charges": 3,
"healing_time": 220,
"healing_value": 5.0,
"recovery_effect_amplifier": 0,
"recovery_effect_duration": 120
}
@@ -0,0 +1,7 @@
{
"healing_charges": 4,
"healing_time": 260,
"healing_value": 5.5,
"recovery_effect_amplifier": 1,
"recovery_effect_duration": 160
}
@@ -0,0 +1,7 @@
{
"healing_charges": 4,
"healing_time": 280,
"healing_value": 6.5,
"recovery_effect_amplifier": 1,
"recovery_effect_duration": 180
}
@@ -0,0 +1,7 @@
{
"healing_charges": 2,
"healing_time": 180,
"healing_value": 3.0,
"recovery_effect_amplifier": 0,
"recovery_effect_duration": 100
}
@@ -0,0 +1,7 @@
{
"healing_charges": 3,
"healing_time": 220,
"healing_value": 4.0,
"recovery_effect_amplifier": 0,
"recovery_effect_duration": 120
}
@@ -0,0 +1,7 @@
{
"healing_charges": 2,
"healing_time": 180,
"healing_value": 2.5,
"recovery_effect_amplifier": 0,
"recovery_effect_duration": 80
}
@@ -0,0 +1,8 @@
{
"type": "sa_combat:hostile_herb_drops",
"conditions": [
{
"condition": "minecraft:killed_by_player"
}
]
}
@@ -0,0 +1,21 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"entries": [
{
"type": "minecraft:item",
"name": "sa_combat:blue_herb"
}
],
"rolls": 1.0
}
],
"random_sequence": "sa_combat:blocks/blue_herb"
}
@@ -0,0 +1,21 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"entries": [
{
"type": "minecraft:item",
"name": "sa_combat:green_herb"
}
],
"rolls": 1.0
}
],
"random_sequence": "sa_combat:blocks/green_herb"
}
@@ -0,0 +1,21 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"entries": [
{
"type": "minecraft:item",
"name": "sa_combat:red_herb"
}
],
"rolls": 1.0
}
],
"random_sequence": "sa_combat:blocks/red_herb"
}
@@ -0,0 +1,21 @@
{
"type": "minecraft:block",
"pools": [
{
"bonus_rolls": 0.0,
"conditions": [
{
"condition": "minecraft:survives_explosion"
}
],
"entries": [
{
"type": "minecraft:item",
"name": "sa_combat:yellow_herb"
}
],
"rolls": 1.0
}
],
"random_sequence": "sa_combat:blocks/yellow_herb"
}
@@ -0,0 +1,15 @@
{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
{
"item": "sa_core:mortar_and_pestle"
},
{
"item": "sa_combat:blue_herb"
}
],
"result": {
"item": "sa_combat:crushed_blue_herb"
}
}
@@ -0,0 +1,15 @@
{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
{
"item": "sa_core:mortar_and_pestle"
},
{
"item": "sa_combat:green_herb"
}
],
"result": {
"item": "sa_combat:crushed_green_herb"
}
}
@@ -0,0 +1,15 @@
{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
{
"item": "sa_core:mortar_and_pestle"
},
{
"item": "sa_combat:red_herb"
}
],
"result": {
"item": "sa_combat:crushed_red_herb"
}
}
@@ -0,0 +1,15 @@
{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
{
"item": "sa_core:mortar_and_pestle"
},
{
"item": "sa_combat:yellow_herb"
}
],
"result": {
"item": "sa_combat:crushed_yellow_herb"
}
}
@@ -0,0 +1,18 @@
{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
{
"item": "sa_combat:tube"
},
{
"item": "sa_combat:crushed_green_herb"
},
{
"item": "sa_combat:crushed_blue_herb"
}
],
"result": {
"item": "sa_combat:mixed_gb_herbs"
}
}
@@ -0,0 +1,18 @@
{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
{
"item": "sa_combat:tube"
},
{
"item": "sa_combat:crushed_green_herb"
},
{
"item": "sa_combat:crushed_green_herb"
}
],
"result": {
"item": "sa_combat:mixed_gg_herbs"
}
}
Loaded 100 of 2439 files, more files were not shown because too many files have changed in this diff. Show more