调整ai数据

This commit is contained in:
Giao committed 2026-10-09 18:08:05 +08:00
1 parent f8c300a4c6
commit c2f5cd98ff
493 files changed
+7 -7

No files matched your search

@@ -0,0 +1,81 @@
# -*- coding: utf-8 -*-
"""给 71 个材料 beh json 添加 netease:customtips 描述,清理 lang 无效 .desc 条目"""
import csv, os, json
BASE = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a'
DROP = {'box_of_nails', 'box_of_paperclips', 'box_of_screws', 'gunpowder_bottle', 'rope'}
SPECIAL = {
'dirty_water_bottle': '饮用可能引起饥饿',
'generator_manual': '学习手册并完成实践训练以操作汽油发电机。',
'matchbox': '点燃方块和火焰',
'sterilized_rags': '清洁医用布。使用后返还脏抹布',
'jerry_can': '用于储存液体:右键液体源收集,Shift+右键倒出',
'saw_blade': '锯子部件,用于制作工具',
'money': '战利品货币',
'money_bundle': '一捆货币',
'blank': '空白物品',
}
META = ('ashen_steel_ingot', 'ashen_steel_mixture', 'ashen_steel_nugget', 'ashen_steel_rod', 'metal_pipe',
'metal_sheet', 'small_metal_sheet', 'scrap_nugget', 'diamond_nugget', 'netherite_nugget')
FABRIC = ('cloth', 'dirty_rags', 'dish_towel', 'fabric_patch', 'fiber_fabric', 'polyester',
'rags', 'sterilized_rags', 'kevlar', 'leather_strip')
THREAD = ('thread', 'kevlar_thread', 'polyester_thread', 'copper_wire', 'insulated_copper_wire', 'wire')
FASTENER = ('nails', 'screws', 'box_of_nails', 'box_of_screws', 'box_of_paperclips', 'paperclip')
SCRAP = ('metal_scrap', 'electric_scrap', 'scrap_wood')
PLASTIC = ('plastic', 'plastic_bag', 'plastic_plate', 'cardboard')
ADHESIVE = ('glue', 'medical_adhesive', 'adhesive_tape', 'duct_tape')
def desc(name):
if name in SPECIAL:
return SPECIAL[name]
if name in META:
return '用于锻造与回收的金属材料。'
if name in SCRAP:
return '可回收利用的材料。'
if name in FABRIC:
return '用于缝制、修复与回收的织物材料。'
if name in THREAD:
return '用于制作与缝合的线材。'
if name in FASTENER:
return '用于组装的紧固件。'
if name in PLASTIC:
return '可用于制作物品的塑料材料。'
if name in ADHESIVE:
return '修复与组装的粘合材料。'
if name in ('battery', 'camera', 'cellphone', 'classic_watch', 'falsh_lights'):
return '可拆解的电子元件。'
if name in ('sulfur', 'sulfur_dust', 'charcoal_dust'):
return '可用于制作的化学材料。'
if name in ('empty_can', 'dented_can', 'tin_can', 'empty_glass_bottle'):
return '空容器,可回收利用。'
if name in ('water_bottle', 'water_bottle2', 'alcohol', 'rubbing_alcohol', 'cleaning_liquid',
'hair_gel', 'fermented_mash', 'gasoline_bucket'):
return '装有液体的容器。'
if name == 'lunch_bag':
return '存放食物的袋子。'
return '合成与回收材料。'
mats = []
with open(os.path.join(BASE, '_sa_materials.csv'), encoding='utf-8-sig') as f:
for row in csv.reader(f):
if row and row[1].endswith('.png') and row[0].isdigit() and row[1][:-4] not in DROP:
mats.append(row[1][:-4])
updated = 0
for m in mats:
p = os.path.join(BASE, 'behavior_pack_kcH4M5u0/netease_items_beh/dn_sa_%s.json' % m)
d = json.load(open(p, encoding='utf-8'))
d['minecraft:item']['components']['netease:customtips'] = {'value': desc(m)}
json.dump(d, open(p, 'w', encoding='utf-8'), ensure_ascii=False, indent=4)
updated += 1
print('beh json 添加 customtips 描述:', updated)
LP = os.path.join(BASE, 'resource_pack_t7eJjrxY/texts/zh_CN.lang')
lines = open(LP, encoding='utf-8').read().splitlines()
keep = [l for l in lines if not (l.startswith('item.dn_sa:') and '.desc=' in l)]
open(LP, 'w', encoding='utf-8').write('\n'.join(keep) + ('\n' if keep else ''))
print('lang 清理 .desc 无效条目:', len(lines) - len(keep), '| 剩余行:', len(keep))
p = os.path.join(BASE, 'behavior_pack_kcH4M5u0/netease_items_beh/dn_sa_metal_scrap.json')
print('示例 metal_scrap components:', json.dumps(json.load(open(p, encoding='utf-8'))['minecraft:item']['components'], ensure_ascii=False))
+29
View File
@@ -0,0 +1,29 @@
# -*- coding: utf-8 -*-
"""给可饮用液体材料添加饮用功能:beh food 组件 + res drink 动画"""
import os, json
BASE = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a'
DRINKS = ['alcohol', 'rubbing_alcohol', 'cleaning_liquid', 'hair_gel', 'fermented_mash']
for m in DRINKS:
# beh json
p = os.path.join(BASE, 'behavior_pack_kcH4M5u0/netease_items_beh/dn_sa_%s.json' % m)
d = json.load(open(p, encoding='utf-8'))
c = d['minecraft:item']['components']
c['minecraft:use_duration'] = 32
c['minecraft:food'] = {
'nutrition': 2,
'saturation_modifier': 'low',
'can_always_eat': True
}
json.dump(d, open(p, 'w', encoding='utf-8'), ensure_ascii=False, indent=4)
# res json
rp = os.path.join(BASE, 'resource_pack_t7eJjrxY/netease_items_res/dn_sa_%s.json' % m)
r = json.load(open(rp, encoding='utf-8'))
r['minecraft:item']['components']['minecraft:use_animation'] = 'drink'
json.dump(r, open(rp, 'w', encoding='utf-8'), ensure_ascii=False, indent=4)
print('已添加饮用功能:', m)
# 验证
p = os.path.join(BASE, 'behavior_pack_kcH4M5u0/netease_items_beh/dn_sa_alcohol.json')
print(json.dumps(json.load(open(p, encoding='utf-8'))['minecraft:item']['components'], ensure_ascii=False, indent=1))
+120
View File
@@ -0,0 +1,120 @@
# -*- coding: utf-8 -*-
"""把 sa_core 76 个材料做成网易版 AddOn 物品:beh json + res json + item_texture + zh_CN.lang + 贴图"""
import csv, os, json, shutil
BASE = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a'
BEH = os.path.join(BASE, 'behavior_pack_kcH4M5u0', 'netease_items_beh')
RES = os.path.join(BASE, 'resource_pack_t7eJjrxY', 'netease_items_res')
TEX = os.path.join(BASE, 'resource_pack_t7eJjrxY', 'textures', 'items')
SRC_TEX = os.path.join(BASE, '_sa_material_textures')
ITEM_TEX = os.path.join(BASE, 'resource_pack_t7eJjrxY', 'textures', 'item_texture.json')
LANG = os.path.join(BASE, 'resource_pack_t7eJjrxY', 'texts', 'zh_CN.lang')
# 读取材料清单(序号,贴图文件,物品ID,中文名,英文名,路径)
mats = []
with open(os.path.join(BASE, '_sa_materials.csv'), encoding='utf-8-sig') as f:
for row in csv.reader(f):
if row and row[1].endswith('.png') and row[0].isdigit():
mats.append((row[1][:-4], row[3])) # (name, zh)
# 描述:特判字典 + 关键词兜底
SPECIAL = {
'dirty_water_bottle': '饮用可能引起饥饿',
'generator_manual': '学习手册并完成实践训练以操作汽油发电机。',
'matchbox': '点燃方块和火焰',
'sterilized_rags': '清洁医用布。使用后返还脏抹布',
'rope': '可放置且可攀爬,落上时可防止摔落伤害',
'jerry_can': '用于储存液体:右键液体源收集,Shift+右键倒出',
'saw_blade': '锯子部件,用于制作工具',
'money': '战利品货币',
'money_bundle': '一捆货币',
'blank': '',
}
META_KEYS = ('ashen_steel_ingot', 'ashen_steel_mixture', 'ashen_steel_nugget', 'ashen_steel_rod',
'metal_pipe', 'metal_sheet', 'small_metal_sheet', 'scrap_nugget',
'diamond_nugget', 'netherite_nugget')
FABRIC_KEYS = ('cloth', 'dirty_rags', 'dish_towel', 'fabric_patch', 'fiber_fabric', 'polyester',
'rags', 'sterilized_rags', 'kevlar', 'leather_strip')
THREAD_KEYS = ('thread', 'kevlar_thread', 'polyester_thread', 'copper_wire', 'insulated_copper_wire', 'wire')
FASTENER_KEYS = ('nails', 'screws', 'box_of_nails', 'box_of_screws', 'box_of_paperclips', 'paperclip')
SCRAP_KEYS = ('metal_scrap', 'electric_scrap', 'scrap_wood')
PLASTIC_KEYS = ('plastic', 'plastic_bag', 'plastic_plate', 'cardboard')
ADHESIVE_KEYS = ('glue', 'medical_adhesive', 'adhesive_tape', 'duct_tape')
def make_desc(name, zh):
if name in SPECIAL:
return SPECIAL[name]
if name in META_KEYS:
return '用于锻造与回收的金属材料。'
if name in SCRAP_KEYS:
return '可回收利用的材料。'
if name in FABRIC_KEYS:
return '用于缝制、修复与回收的织物材料。'
if name in THREAD_KEYS:
return '用于制作与缝合的线材。'
if name in FASTENER_KEYS:
return '用于组装的紧固件。'
if name in PLASTIC_KEYS:
return '可用于制作物品的塑料材料。'
if name in ADHESIVE_KEYS:
return '修复与组装的粘合材料。'
if name in ('battery', 'camera', 'cellphone', 'classic_watch', 'falsh_lights'):
return '可拆解的电子元件。'
if name in ('sulfur', 'sulfur_dust', 'charcoal_dust', 'gunpowder_bottle'):
return '可用于制作的化学材料。'
if name in ('empty_can', 'dented_can', 'tin_can', 'empty_glass_bottle'):
return '空容器,可回收利用。'
if name in ('water_bottle', 'water_bottle2', 'alcohol', 'rubbing_alcohol', 'cleaning_liquid',
'hair_gel', 'fermented_mash', 'gasoline_bucket'):
return '装有液体的容器。'
if name in ('lunch_bag',):
return '存放食物的袋子。'
return '合成与回收材料。'
# 1) 生成 beh / res json + 复制贴图
beh_tpl = {'format_version': '1.10', 'minecraft:item': {
'components': {'minecraft:max_stack_size': 64},
'description': {'category': 'dn_sa', 'identifier': 'dn_sa:%s'}}}
res_tpl = {'format_version': '1.10', 'minecraft:item': {
'components': {'minecraft:icon': 'dn_sa:%s'},
'description': {'identifier': 'dn_sa:%s'}}}
count = 0
for name, zh in mats:
beh_path = os.path.join(BEH, 'dn_sa_%s.json' % name)
res_path = os.path.join(RES, 'dn_sa_%s.json' % name)
with open(beh_path, 'w', encoding='utf-8') as f:
json.dump(beh_tpl, f, ensure_ascii=False, indent=4)
with open(res_path, 'w', encoding='utf-8') as f:
json.dump(res_tpl, f, ensure_ascii=False, indent=4)
shutil.copy2(os.path.join(SRC_TEX, name + '.png'), os.path.join(TEX, name + '.png'))
count += 1
print('已生成物品 json + 复制贴图:', count)
# 2) item_texture.json 追加
with open(ITEM_TEX, encoding='utf-8') as f:
it = json.load(f)
added = 0
for name, zh in mats:
key = 'dn_sa:%s' % name
if key not in it['texture_data']:
it['texture_data'][key] = {'textures': 'textures/items/%s' % name}
added += 1
with open(ITEM_TEX, 'w', encoding='utf-8') as f:
json.dump(it, f, ensure_ascii=False, indent=4)
print('item_texture.json 新增条目:', added, '| 总数:', len(it['texture_data']))
# 3) zh_CN.lang 追加 name + desc
lang = open(LANG, encoding='utf-8').read()
lines_added = 0
new_lines = []
existing = set(lang.splitlines())
for name, zh in mats:
nk = 'item.dn_sa:%s.name=%s' % (name, zh)
dk = 'item.dn_sa:%s.desc=%s' % (name, make_desc(name, zh))
if nk not in existing:
new_lines.append(nk); new_lines.append(dk); lines_added += 2
if new_lines:
with open(LANG, 'a', encoding='utf-8') as f:
f.write('\n' + '\n'.join(new_lines) + '\n')
print('zh_CN.lang 追加条目:', lines_added)
@@ -0,0 +1,33 @@
import zipfile, os, subprocess
jar = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out\sa_decor-forge-1.20.1-1.0.3.jar'
out = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out\_tmp\classes'
targets = [
'com/ogaba/sa_decor/command/SADecorLootCommand.class',
'com/ogaba/sa_decor/common/loot/DecorLootConfigManager.class',
]
with zipfile.ZipFile(jar) as z:
for t in targets:
p = os.path.join(out, t.replace('/', os.sep))
os.makedirs(os.path.dirname(p), exist_ok=True)
with open(p, 'wb') as f:
f.write(z.read(t))
print('extracted:', t)
javap = r'D:\我的世界\bin\javap.EXE'
for t in targets:
cname = t[:-6].replace('/', '.')
r = subprocess.run([javap, '-c', '-p', '-classpath', out, cname], capture_output=True, text=True, encoding='utf-8', errors='replace')
text = r.stdout if r.returncode == 0 else r.stderr
with open(os.path.join(out, cname.replace('.', '_') + '.txt'), 'w', encoding='utf-8') as f:
f.write(text)
print('\n=====', cname, '=====')
# 输出含 Survivor 的行上下文
lines = text.splitlines()
for i, line in enumerate(lines):
if 'Survivor' in line or 'Arsenal' in line:
for j in range(max(0, i-2), min(len(lines), i+4)):
print(lines[j])
print('---')
@@ -0,0 +1,18 @@
# -*- coding: utf-8 -*-
from PIL import Image
import os
base = r"e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\resource_pack_t7eJjrxY\textures\items"
# 打印若干物品贴图尺寸对比
for n in ["burrito", "burrito_rotten", "hot_dog", "taco", "jianbing"]:
p = os.path.join(base, n + ".png")
if os.path.exists(p):
im = Image.open(p)
print(n, im.size, im.mode, os.path.getsize(p))
# 校验 jianbing 是否是有效完整PNG且内容是煎饼(采样角点颜色)
p = os.path.join(base, "jianbing.png")
im = Image.open(p)
im.load()
print("jianbing corners:", im.getpixel((0,0)), im.getpixel((15,0)), im.getpixel((0,15)), im.getpixel((15,15)))
print("jianbing center:", im.getpixel((8,8)))
+21
View File
@@ -0,0 +1,21 @@
import zipfile
base = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out'
jars = {
'essentials': base + r'\sa_essentials-forge-1.20.1-1.0.0.jar',
'lib': base + r'\sa_lib-forge-1.20.1-1.0.1.jar',
'decor': base + r'\sa_decor-forge-1.20.1-1.0.3.jar',
}
import json
for name, jar in jars.items():
print('='*30, name, '='*30)
with zipfile.ZipFile(jar) as z:
for n in z.namelist():
if n.startswith('assets/') and n.endswith('/lang/zh_cn.json'):
data = json.loads(z.read(n).decode('utf-8'))
print('---', n, '---')
for k, v in data.items():
if 'mod' in k or 'arsenal' in k.lower() or 'survivor' in k.lower() or 'creative' in k or 'tab' in k:
print(f' {k} = {v}')
print()
@@ -0,0 +1,175 @@
== com.ogaba.sa_combat.client.event.SACombatClientForgeEvents ==
item.durability
[a-z0-9_.-]+:[a-z0-9_./-]+
item.modifiers.mainhand
attack damage
attack speed
attack range
entity reach
attack knockback
dano de ataque
velocidade de ataque
alcance de ataque
repuls
knockback
when in main hand
main hand
m?o principal
mao principal
%.2f
������...
renderSpyglassOverlay
== com.ogaba.sa_combat.client.render.PlayerArmSkinLayer ==
root
base
slim
right_hand_wide
right_hand_slim
left_hand_wide
left_hand_slim
== com.ogaba.sa_combat.client.render.SAWeaponItemRenderer ==
idle_view
camera
right_hand_wide
left_hand_wide
right_hand_slim
left_hand_slim
spyglass
== com.ogaba.sa_combat.client.render.SpecialGrenadeItemRenderer ==
camera
idle_view
held_item
granade
right_hand
left_hand
right_hand_wide
left_hand_wide
right_hand_slim
left_hand_slim
item/pipe_bomb_visual
item/nail_bomb_visual
item/molotov_visual
== com.ogaba.sa_combat.client.render.SpecialGrenadePlayerArmSkinLayer ==
main
right
left
right_hand
left_hand
granade
camera
right_hand_wide
right_hand_slim
left_hand_wide
left_hand_slim
slim
== com.ogaba.sa_combat.client.tooltip.BlueprintClientTooltipComponent ==
tooltip.sa_combat.blueprint.unknown
Unknown Unlock
tooltip.sa_combat.blueprint.check_data
Check blueprint data
tooltip.sa_combat.blueprint.unlock
Unlock
tooltip.sa_combat.blueprint.recipe_unlock
Recipe Unlock
����
tooltip.sa_combat.blueprint.no_abilities
No abilities
tooltip.sa_combat.blueprint.on_hit
On Hit
����
bettercombat
attack_range
����
����
%.1f
== com.ogaba.sa_combat.client.tooltip.WeaponClientTooltipComponent ==
tooltip.sa_combat.modifier_section
tooltip.sa_combat.on_hit
tooltip.sa_combat.empty_socket
== com.ogaba.sa_combat.event.SACombatForgeEvents ==
SA Combat TACZ vest bullet resistance
SA Combat weapon upgrade damage
SA Combat weapon upgrade speed
SA Combat weapon upgrade knockback
SA Combat weapon upgrade reach
SACombatLastShieldThornsTick
SACombatLastShieldThornsTick
spiked
13a24b02-d971-4ee7-879c-1c7068a6bb71
457d3b0c-c7b7-43a4-8395-01f82ec1bdb2
df109f67-5b6d-4de4-9a1b-c75443c0f1b2
9d46b9e9-46cb-4ab3-b2a0-c0e331cce312
11d92754-4e96-4c9e-9b25-d8945bc43b24
tacz
tacz.bullet_resistance
== com.ogaba.sa_survival.client.BackpackGuiKeyHandler ==
key.sa_combat.open_backpack_gui
key.categories.sa_combat
== com.ogaba.sa_survival.client.BackpackInventoryPanelOverlay$SlotVisualState ==
NONE
ACTIVE
LOCKED
EMPTY
== com.ogaba.sa_survival.client.BackpackInventoryPanelOverlay ==
pink
blue
jeans
green
yellow
desert
black
camo
olive
military
tactical
vest
jacket
leather
brown
shirt
f_40220_
f_40221_
[SA Survival] Could not access Slot position fields for modular inventory slots.
����
�������IJ�λ
�˱����޷�ʹ�õIJ�λ
screen.sa_combat.utility_panel.close
screen.sa_combat.utility_panel.open
== com.ogaba.sa_survival.client.renderer.BackpackCurioRenderer$WeaponMountSide ==
RIGHT
LEFT
== com.ogaba.sa_survival.client.renderer.BackpackCurioRenderer ==
SatchelCurioRender
Expected 3 double values
Expected 3 float values
== com.ogaba.sa_survival.client.renderer.FlashlightItemRenderer ==
right_hand_wide
right_hand_slim
left_hand_wide
left_hand_slim
item/flashlight_emissive
== com.ogaba.sa_survival.client.tooltip.ClientBackpackContentsTooltip ==
pink
yellow
desert
blue
jeans
green
camo
black
jacket
vest
== com.ogaba.sa_survival.event.ExternalEquipmentStorageTooltipEvents ==
extra slots
��סShift��Ԥ������
��סShift��Ԥ������
== com.ogaba.sa_survival.item.tooltip.BackpackContentsTooltip ==
Items
ClothingItems
== com.ogaba.sa_survival.item.tooltip.EffectTooltipUtil ==
tooltip.sa_combat.effects
tooltip.sa_combat.removes_poison
tooltip.sa_combat.removes_bleeding
tooltip.sa_combat.heals_amount
potion.withAmplifier
potion.withDuration
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
"""剔除 cellphone(手机,带模型)"""
import os, json
BASE = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a'
DROP = ['cellphone']
for sub in ['behavior_pack_kcH4M5u0/netease_items_beh', 'resource_pack_t7eJjrxY/netease_items_res']:
for m in DROP:
p = os.path.join(BASE, sub, 'dn_sa_%s.json' % m)
if os.path.exists(p):
os.remove(p)
p = os.path.join(BASE, 'resource_pack_t7eJjrxY/textures/items/cellphone.png')
if os.path.exists(p):
os.remove(p)
IP = os.path.join(BASE, 'resource_pack_t7eJjrxY/textures/item_texture.json')
it = json.load(open(IP, encoding='utf-8'))
it['texture_data'].pop('dn_sa:cellphone', None)
json.dump(it, open(IP, 'w', encoding='utf-8'), ensure_ascii=False, indent=4)
LP = os.path.join(BASE, 'resource_pack_t7eJjrxY/texts/zh_CN.lang')
lines = open(LP, encoding='utf-8').read().splitlines()
keep = [l for l in lines if not l.startswith('item.dn_sa:cellphone.')]
open(LP, 'w', encoding='utf-8').write('\n'.join(keep) + ('\n' if keep else ''))
beh = [f for f in os.listdir(os.path.join(BASE, 'behavior_pack_kcH4M5u0/netease_items_beh')) if f.endswith('.json')]
print('beh json 总数:', len(beh), '| 材料数:', len(beh) - 44)
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
"""剔除 dirty_water_bottle(脏水瓶,带模型)"""
import os, json
BASE = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a'
DROP = ['dirty_water_bottle']
for sub in ['behavior_pack_kcH4M5u0/netease_items_beh', 'resource_pack_t7eJjrxY/netease_items_res']:
for m in DROP:
p = os.path.join(BASE, sub, 'dn_sa_%s.json' % m)
if os.path.exists(p):
os.remove(p)
p = os.path.join(BASE, 'resource_pack_t7eJjrxY/textures/items/dirty_water_bottle.png')
if os.path.exists(p):
os.remove(p)
IP = os.path.join(BASE, 'resource_pack_t7eJjrxY/textures/item_texture.json')
it = json.load(open(IP, encoding='utf-8'))
it['texture_data'].pop('dn_sa:dirty_water_bottle', None)
json.dump(it, open(IP, 'w', encoding='utf-8'), ensure_ascii=False, indent=4)
LP = os.path.join(BASE, 'resource_pack_t7eJjrxY/texts/zh_CN.lang')
lines = open(LP, encoding='utf-8').read().splitlines()
keep = [l for l in lines if not l.startswith('item.dn_sa:dirty_water_bottle.')]
open(LP, 'w', encoding='utf-8').write('\n'.join(keep) + ('\n' if keep else ''))
beh = [f for f in os.listdir(os.path.join(BASE, 'behavior_pack_kcH4M5u0/netease_items_beh')) if f.endswith('.json')]
print('beh json 总数:', len(beh), '| 材料数:', len(beh) - 44)
+28
View File
@@ -0,0 +1,28 @@
# -*- coding: utf-8 -*-
"""剔除 jerry_can(油桶,带模型)"""
import os, json
BASE = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a'
DROP = ['jerry_can']
for sub in ['behavior_pack_kcH4M5u0/netease_items_beh', 'resource_pack_t7eJjrxY/netease_items_res']:
for m in DROP:
p = os.path.join(BASE, sub, 'dn_sa_%s.json' % m)
if os.path.exists(p):
os.remove(p)
p = os.path.join(BASE, 'resource_pack_t7eJjrxY/textures/items/jerry_can.png')
if os.path.exists(p):
os.remove(p)
IP = os.path.join(BASE, 'resource_pack_t7eJjrxY/textures/item_texture.json')
it = json.load(open(IP, encoding='utf-8'))
it['texture_data'].pop('dn_sa:jerry_can', None)
json.dump(it, open(IP, 'w', encoding='utf-8'), ensure_ascii=False, indent=4)
LP = os.path.join(BASE, 'resource_pack_t7eJjrxY/texts/zh_CN.lang')
lines = open(LP, encoding='utf-8').read().splitlines()
keep = [l for l in lines if not l.startswith('item.dn_sa:jerry_can.')]
open(LP, 'w', encoding='utf-8').write('\n'.join(keep) + ('\n' if keep else ''))
beh = [f for f in os.listdir(os.path.join(BASE, 'behavior_pack_kcH4M5u0/netease_items_beh')) if f.endswith('.json')]
print('beh json 总数:', len(beh), '| 材料数:', len(beh) - 44)
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
"""剔除 water_bottle / water_bottle2 / blank 三个材料(水瓶带模型、空白为占位物品)"""
import os, json
BASE = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a'
DROP = ['water_bottle', 'water_bottle2', 'blank']
# 1) 删 beh/res json + 贴图
for sub in ['behavior_pack_kcH4M5u0/netease_items_beh', 'resource_pack_t7eJjrxY/netease_items_res']:
for m in DROP:
p = os.path.join(BASE, sub, 'dn_sa_%s.json' % m)
if os.path.exists(p):
os.remove(p)
print('删', sub.split('/')[-1], m)
for m in DROP:
p = os.path.join(BASE, 'resource_pack_t7eJjrxY/textures/items/%s.png' % m)
if os.path.exists(p):
os.remove(p)
print('删贴图', m)
# 2) item_texture.json 移除
IP = os.path.join(BASE, 'resource_pack_t7eJjrxY/textures/item_texture.json')
it = json.load(open(IP, encoding='utf-8'))
for m in DROP:
it['texture_data'].pop('dn_sa:%s' % m, None)
json.dump(it, open(IP, 'w', encoding='utf-8'), ensure_ascii=False, indent=4)
print('item_texture 移除后条数:', len(it['texture_data']))
# 3) zh_CN.lang 移除 name 行
LP = os.path.join(BASE, 'resource_pack_t7eJjrxY/texts/zh_CN.lang')
lines = open(LP, encoding='utf-8').read().splitlines()
keep = []
removed = 0
for l in lines:
if any(('item.dn_sa:%s.' % m) in l for m in DROP):
removed += 1
continue
keep.append(l)
open(LP, 'w', encoding='utf-8').write('\n'.join(keep) + ('\n' if keep else ''))
print('lang 移除行:', removed, '| 剩余行:', len(keep))
# 4) 最终数量
beh = [f for f in os.listdir(os.path.join(BASE, 'behavior_pack_kcH4M5u0/netease_items_beh')) if f.endswith('.json')]
print('beh json 总数:', len(beh))
print('材料数:', len(beh) - 44)
+23
View File
@@ -0,0 +1,23 @@
import zipfile, json, os
base = r"e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out"
jar = os.path.join(base, "sa_decor-forge-1.20.1-1.0.3.jar")
def load(z, n):
return json.loads(z.read(n).decode('utf-8'))
with zipfile.ZipFile(jar) as z:
en = load(z, "assets/sa_decor/lang/en_us.json")
pt = load(z, "assets/sa_decor/lang/pt_br.json")
zh = load(z, "assets/sa_decor/lang/zh_cn.json")
keys = sorted(set(en) | set(pt) | set(zh))
out = []
for k in keys:
e = en.get(k, "")
p = pt.get(k, "")
c = zh.get(k, "")
out.append(f"{k}\n EN: {e}\n PT: {p}\n ZH: {c}")
with open(os.path.join(base, "_tmp", "decor_lang.txt"), "w", encoding="utf-8") as f:
f.write("\n".join(out))
f.write(f"\nTOTAL {len(keys)}\n")
+12
View File
@@ -0,0 +1,12 @@
import zipfile, json, sys, io, os
base = r"e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out"
jars = [f for f in os.listdir(base) if f.endswith('.jar')]
for j in jars:
p = os.path.join(base, j)
print("=" * 30, j)
with zipfile.ZipFile(p) as z:
names = [n for n in z.namelist() if '/lang/' in n]
for n in names:
print(" ", n)
@@ -0,0 +1,25 @@
import zipfile, os, subprocess
jar = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out\sa_essentials-forge-1.20.1-1.0.0.jar'
out = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out\_tmp\classes'
targets = [
'com/ogaba/sa_survival/item/tooltip/BackpackContentsTooltip.class',
'com/ogaba/sa_survival/event/ExternalEquipmentStorageTooltipEvents.class',
'com/ogaba/sa_combat/event/SACombatForgeEvents.class',
]
javap = r'D:\我的世界\bin\javap.EXE'
for t in targets:
p = os.path.join(out, t.replace('/', os.sep))
os.makedirs(os.path.dirname(p), exist_ok=True)
with zipfile.ZipFile(jar) as z:
with open(p, 'wb') as f:
f.write(z.read(t))
cname = t[:-6].replace('/', '.')
r = subprocess.run([javap, '-c', '-p', '-classpath', out, cname], capture_output=True, text=True, encoding='utf-8', errors='replace')
text = r.stdout if r.returncode == 0 else r.stderr
fn = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out\_tmp\javap_%s.txt' % cname.rsplit('.',1)[-1]
with open(fn, 'w', encoding='utf-8') as f:
f.write(text)
print('==', cname, 'written:', fn)
@@ -0,0 +1,45 @@
import zipfile, os, subprocess, shutil
jar = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out\sa_essentials-forge-1.20.1-1.0.0.jar'
out = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out\_tmp\classes'
os.makedirs(out, exist_ok=True)
targets = [
'com/ogaba/sa_combat/client/tooltip/BlueprintClientTooltipComponent.class',
'com/ogaba/sa_combat/client/tooltip/BlueprintClientTooltipComponent$1.class',
'com/ogaba/sa_combat/item/BlueprintTooltipComponent.class',
'com/ogaba/sa_combat/item/BlueprintItem.class',
'com/ogaba/sa_combat/blueprint/BlueprintDefinitionRegistry$Definition.class',
'com/ogaba/sa_combat/blueprint/BlueprintDefinitionRegistry.class',
]
with zipfile.ZipFile(jar) as z:
for t in targets:
data = z.read(t)
p = os.path.join(out, t.replace('/', os.sep))
os.makedirs(os.path.dirname(p), exist_ok=True)
with open(p, 'wb') as f:
f.write(data)
print('extracted:', t)
# javap 反编译查看渲染逻辑
javap = shutil.which('javap')
if javap is None:
# 尝试常见 JDK 路径
for cand in [r'C:\Program Files\Java\jdk-17\bin\javap.exe',
r'C:\Program Files\Java\jdk-21\bin\javap.exe',
r'C:\Program Files\Microsoft\jdk-17.0.11\bin\javap.exe',
r'C:\Program Files\Eclipse Adoptium\jdk-17.0.13.11-hotspot\bin\javap.exe']:
if os.path.exists(cand):
javap = cand
break
print('javap =', javap)
if javap:
for t in targets:
cname = t[:-6].replace('/', '.')
r = subprocess.run([javap, '-c', '-p', '-classpath', out, cname], capture_output=True, text=True, encoding='utf-8', errors='replace')
print('\n' + '='*20, cname, '='*20)
print(r.stdout[:6000] if r.returncode == 0 else r.stderr[:3000])
else:
print('javap NOT FOUND')
@@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
import zipfile, os, subprocess
jars = [
r"e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out\sa_core-forge-1.20.1-1.0.1.jar",
r"e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out\sa_lib-forge-1.20.1-1.0.1.jar",
r"e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out\sa_decor-forge-1.20.1-1.0.3.jar",
r"e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out\sa_essentials-forge-1.20.1-1.0.0.jar",
]
TARGET = "com/ogaba/sacore/content/item/tool/MatchboxItem.class"
OUT = r"C:\Users\30272\AppData\Local\Temp\sa_check\javap_jar\out"
found = None
for j in jars:
if os.path.exists(j):
try:
with zipfile.ZipFile(j) as z:
for n in z.namelist():
if n.endswith("MatchboxItem.class") and "tool" in n:
found = (j, n)
print("FOUND in", j, "->", n)
break
except Exception as e:
print("ERR", j, e)
if found:
jar, name = found
dstdir = os.path.join(OUT, "com", "ogaba", "sacore", "content", "item", "tool")
os.makedirs(dstdir, exist_ok=True)
dst = os.path.join(dstdir, "MatchboxItem.class")
with zipfile.ZipFile(jar) as z:
with z.open(name) as src, open(dst, "wb") as out_f:
out_f.write(src.read())
print("EXTRACTED to", dst)
cfr = r"C:\Users\30272\AppData\Local\Temp\sa_check\javap_jar\cfr.jar"
r = subprocess.run(["java", "-jar", cfr, dst, "--outputdir", dstdir],
capture_output=True, text=True, timeout=120)
print("CFR stdout:", r.stdout[-2000:] if r.stdout else "")
print("CFR stderr:", r.stderr[-2000:] if r.stderr else "")
+34
View File
@@ -0,0 +1,34 @@
import zipfile, re
base = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out'
jars = {
'essentials': base + r'\sa_essentials-forge-1.20.1-1.0.0.jar',
'lib': base + r'\sa_lib-forge-1.20.1-1.0.1.jar',
'decor': base + r'\sa_decor-forge-1.20.1-1.0.3.jar',
}
pat = re.compile(r"Survivors?\s+Arsenal", re.IGNORECASE)
for name, jar in jars.items():
hits = []
with zipfile.ZipFile(jar) as z:
for n in z.namelist():
if n.endswith('/') or n.endswith('.png'):
continue
if n.endswith('.class'):
try:
b = z.read(n)
# class 文件只查 ASCII 字符串
s = ''.join(chr(c) for c in b if 32 <= c < 127 or c in (9, 10, 13))
except Exception:
continue
else:
try:
s = z.read(n).decode('utf-8', errors='ignore')
except Exception:
continue
if pat.search(s):
hits.append(n)
print(f'[{name}] 英文 mod 名残留(除 lang 文件): {len(hits)} 个')
for h in hits:
if not ('/lang/' in h):
print(' ', h)
+31
View File
@@ -0,0 +1,31 @@
import zipfile, json, os
base = r"e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out"
tokens = ["pastel","coxinha","brigadeiro","pacoquita","wind","chips","cheese_bread",
"cereal","cracker","guarana","duff","burger","hot_dog","taco","donut","waffle",
"biscuit","toast","burrito","candy","jam","cheese","butter","peanut","granola",
"energy","vodka","whiskey","wine","beer","cola","pepsi","fanta","monster","coffee"]
langs = {
"sa_decor-forge-1.20.1-1.0.3.jar": "assets/sa_decor/lang/",
"sa_essentials-forge-1.20.1-1.0.0.jar": "assets/sa_combat/lang/",
"sa_lib-forge-1.20.1-1.0.1.jar": "assets/sa_core/lang/",
}
lines = []
for jar, langdir in langs.items():
p = os.path.join(base, jar)
with zipfile.ZipFile(p) as z:
names = set(z.namelist())
en = json.loads(z.read(langdir + "en_us.json").decode('utf-8')) if langdir + "en_us.json" in names else {}
pt = json.loads(z.read(langdir + "pt_br.json").decode('utf-8')) if langdir + "pt_br.json" in names else {}
zh = json.loads(z.read(langdir + "zh_cn.json").decode('utf-8')) if langdir + "zh_cn.json" in names else {}
hits = [k for k in (set(en) | set(pt) | set(zh))
if any(t in k.lower() or t in str(en.get(k,'')).lower() or t in str(pt.get(k,'')).lower() for t in tokens)]
lines.append("=" * 30 + " " + jar + f" hits={len(hits)}")
for k in sorted(hits):
lines.append(f"{k}\n EN: {en.get(k,'')}\n PT: {pt.get(k,'')}\n ZH: {zh.get(k,'')}")
with open(os.path.join(base, "_tmp", "food_all.txt"), "w", encoding="utf-8") as f:
f.write("\n".join(lines))
print("done")
+16
View File
@@ -0,0 +1,16 @@
# -*- coding: utf-8 -*-
import os, glob, shutil
d = r"e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\resource_pack_t7eJjrxY\textures\items"
# listdir 返回磁盘上的真实文件名(保留大小写)
names = os.listdir(d)
print("all *ianbing* in dir:", [n for n in names if "ianbing" in n.lower() and n.lower().endswith(".png")])
target = os.path.join(d, "jianbing.png")
for n in names:
if n.lower() == "jianbing.png" and n != "jianbing.png":
src = os.path.join(d, n)
# 复制到小写目标(覆盖),再删除大小写不同的旧名
shutil.copyfile(src, target)
os.remove(src)
print("normalized", n, "->", "jianbing.png")
print("final files:", [os.path.basename(x) for x in glob.glob(d + r"\*ianbing*.png")])
print("lowercase exists:", os.path.exists(target))
@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
"""对齐 Java 版饮用效果:3 个有毒饮品加中毒+反胃;发胶/发酵糊移除饮用功能"""
import os, json
BASE = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a'
TOXIC = ['alcohol', 'rubbing_alcohol', 'cleaning_liquid']
PLAIN = ['hair_gel', 'fermented_mash']
# 1) 3 个有毒饮品:food 加 effects(中毒 II 10s + 反胃 15s)
for m in TOXIC:
p = os.path.join(BASE, 'behavior_pack_kcH4M5u0/netease_items_beh/dn_sa_%s.json' % m)
d = json.load(open(p, encoding='utf-8'))
c = d['minecraft:item']['components']
c['minecraft:food']['effects'] = [
{'name': 'poison', 'chance': 1.0, 'duration': 10, 'amplifier': 1},
{'name': 'nausea', 'chance': 1.0, 'duration': 15, 'amplifier': 0}
]
json.dump(d, open(p, 'w', encoding='utf-8'), ensure_ascii=False, indent=4)
print('加效果:', m)
# 2) 发胶/发酵糊:移除饮用功能(恢复普通物品)
for m in PLAIN:
p = os.path.join(BASE, 'behavior_pack_kcH4M5u0/netease_items_beh/dn_sa_%s.json' % m)
d = json.load(open(p, encoding='utf-8'))
c = d['minecraft:item']['components']
c.pop('minecraft:food', None)
c.pop('minecraft:use_duration', None)
json.dump(d, open(p, 'w', encoding='utf-8'), ensure_ascii=False, indent=4)
rp = os.path.join(BASE, 'resource_pack_t7eJjrxY/netease_items_res/dn_sa_%s.json' % m)
r = json.load(open(rp, encoding='utf-8'))
r['minecraft:item']['components'].pop('minecraft:use_animation', None)
json.dump(r, open(rp, 'w', encoding='utf-8'), ensure_ascii=False, indent=4)
print('移除饮用:', m)
# 验证
p = os.path.join(BASE, 'behavior_pack_kcH4M5u0/netease_items_beh/dn_sa_alcohol.json')
print(json.dumps(json.load(open(p, encoding='utf-8'))['minecraft:item']['components'], ensure_ascii=False))
@@ -0,0 +1,34 @@
import zipfile, os, re, shutil
jar = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out\sa_lib-forge-1.20.1-1.0.1.jar'
with zipfile.ZipFile(jar) as z:
infos = z.infolist()
data = {i.filename: z.read(i) for i in infos}
meta = 'META-INF/mods.toml'
text = data[meta].decode('utf-8')
new_text = re.sub(
r"description\s*=\s*'''[\s\S]*?'''",
"description='''\n我们所有幸存者军火库模组的公共库。\n'''",
text,
count=1,
)
print('changed:', new_text != text)
print(new_text[:400])
if new_text != text:
data[meta] = new_text.encode('utf-8')
tmp = jar + '.tmp'
with zipfile.ZipFile(tmp, 'w', zipfile.ZIP_DEFLATED) as z:
for i in infos:
z.writestr(i, data[i.filename])
shutil.move(tmp, jar)
print('jar updated.')
# verify
with zipfile.ZipFile(jar) as z:
t = z.read(meta).decode('utf-8')
for line in t.splitlines():
if 'displayName' in line or 'description' in line:
print('VERIFY:', line.strip())
print('entries=', len(z.namelist()), 'testzip=', z.testzip())
@@ -0,0 +1,68 @@
import zipfile, os, re, shutil
base = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out'
jars = {
'essentials': base + r'\sa_essentials-forge-1.20.1-1.0.0.jar',
'lib': base + r'\sa_lib-forge-1.20.1-1.0.1.jar',
'decor': base + r'\sa_decor-forge-1.20.1-1.0.3.jar',
}
# 每个 jar 的 mods.toml 替换规则:(旧字符串, 新字符串) 或 (正则, 新, is_regex)
repls = {
'essentials': [
('displayName = "Survivors Arsenal: Essentials"',
'displayName = "幸存者军火库:基础包"'),
('description = "Combat, survival and essential gameplay content for Survivors Arsenal."',
'description = "幸存者军火库的战斗、生存与核心玩法内容。"'),
],
'lib': [
('displayName="Survivor\'s Arsenal: Lib"',
'displayName="幸存者军火库:核心"'),
(r"description\s*=\s*'''[\s\S]*?'''",
"description='''\n我们所有幸存者军火库模组的公共库。\n'''"),
],
'decor': [
('displayName="Survivor\'s Arsenal: Loot & Decor"',
'displayName="幸存者军火库:战利品与装饰"'),
('description="Decoration module for Survivor\'s Arsenal."',
'description="幸存者军火库的装饰模块。"'),
],
}
for name, jar in jars.items():
with zipfile.ZipFile(jar) as z:
infos = z.infolist()
data = {i.filename: z.read(i) for i in infos}
meta = 'META-INF/mods.toml'
text = data[meta].decode('utf-8')
orig = text
for old, new in repls[name]:
if text.find(old) != -1:
text = text.replace(old, new)
print(f'[{name}] replaced: {old[:60]!r}')
else:
print(f'[{name}] WARN not found: {old[:60]!r}')
if text == orig:
print(f'[{name}] NO CHANGES!')
continue
data[meta] = text.encode('utf-8')
# 重建 jar
tmp = jar + '.tmp'
with zipfile.ZipFile(tmp, 'w', zipfile.ZIP_DEFLATED) as z:
for i in infos:
z.writestr(i, data[i.filename])
shutil.move(tmp, jar)
print(f'[{name}] jar updated.')
# 验证
print('\n===== VERIFY =====')
for name, jar in jars.items():
with zipfile.ZipFile(jar) as z:
t = z.read('META-INF/mods.toml').decode('utf-8')
for line in t.splitlines():
if 'displayName' in line or 'description' in line:
print(f'[{name}] {line.strip()}')
# 检查 jar 完好
bad = z.testzip()
print(f'[{name}] entries={len(z.namelist())} testzip={bad}')
@@ -0,0 +1,42 @@
import zipfile, os, shutil
base = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out'
jar = base + r'\sa_essentials-forge-1.20.1-1.0.0.jar'
target = 'com/ogaba/sa_combat/client/event/SACombatClientForgeEvents.class'
old_ascii = b'Reloading...' # 11 字节
old_pat = b'\x01\x00\x0b' + old_ascii # CONSTANT_Utf8 tag + u2 length(11) + bytes
new_utf8 = '换弹中...'.encode('utf-8') # 12 字节 (E6 8D A2 E5 BC B9 E4 B8 AD 2E 2E 2E)
new_pat = b'\x01\x00\x0c' + new_utf8
print('new bytes:', new_utf8.hex())
with zipfile.ZipFile(jar) as z:
infos = z.infolist()
data = {i.filename: z.read(i) for i in infos}
b = data[target]
cnt = b.count(old_pat)
print('occurrences of utf8-const pattern:', cnt)
if cnt != 1:
raise SystemExit('ABORT: expected exactly 1 occurrence')
nb = b.replace(old_pat, new_pat)
print('class size: %d -> %d' % (len(b), len(nb)))
# 验证替换后不再含旧 ASCII(单独出现可能在其他字段;此处仅验证常量池模式消失)
print('old const gone:', nb.count(old_pat) == 0)
data[target] = nb
tmp = jar + '.tmp'
with zipfile.ZipFile(tmp, 'w', zipfile.ZIP_DEFLATED) as z:
for i in infos:
z.writestr(i, data[i.filename])
shutil.move(tmp, jar)
print('jar updated.')
# verify
with zipfile.ZipFile(jar) as z:
nb = z.read(target)
print('new const present:', nb.count(new_pat) == 1)
print('old ascii anywhere in class:', nb.count(old_ascii))
print('entries=', len(z.namelist()), 'testzip=', z.testzip())
@@ -0,0 +1,38 @@
import zipfile, shutil
base = r'e:\MCStudioDownload\work\3027246179@qq.com\Cpp\AddOn\309c2d420bc84ee986db9cdd070ff02a\_sa_hanhua_out'
jar = base + r'\sa_essentials-forge-1.20.1-1.0.0.jar'
target = 'com/ogaba/sa_combat/client/event/SACombatClientForgeEvents.class'
old_ascii = b'Reloading...' # 12 字节
old_pat = b'\x01\x00\x0c' + old_ascii
new_utf8 = '换弹中...'.encode('utf-8') # 12 字节,与旧串等长
assert len(new_utf8) == len(old_ascii), (len(new_utf8), len(old_ascii))
new_pat = b'\x01\x00\x0c' + new_utf8
print('new bytes:', new_utf8.hex(), 'len', len(new_utf8))
with zipfile.ZipFile(jar) as z:
infos = z.infolist()
data = {i.filename: z.read(i) for i in infos}
b = data[target]
cnt = b.count(old_pat)
print('occurrences:', cnt)
assert cnt == 1, 'ABORT'
nb = b.replace(old_pat, new_pat)
assert len(nb) == len(b)
data[target] = nb
tmp = jar + '.tmp'
with zipfile.ZipFile(tmp, 'w', zipfile.ZIP_DEFLATED) as z:
for i in infos:
z.writestr(i, data[i.filename])
shutil.move(tmp, jar)
print('jar updated.')
with zipfile.ZipFile(jar) as z:
nb = z.read(target)
print('new const present:', nb.count(new_pat) == 1)
print('old ascii remains:', nb.count(old_ascii))
print('entries=', len(z.namelist()), 'testzip=', z.testzip())
Loaded 100 of 493 files, more files were not shown because too many files have changed in this diff. Show more