amongus私人服务器搭建
项目地址: https://github.com/Impostor/Impostor
Im的更新还是挺快的,621版本出了就马上更了。
为了搭建方便,于是用docker进行操作。如果直接运行docker的话,里面会有抽风的反作弊系统,私服的话建议关掉反作弊,因此整个流程如下(全程root)
首先需要有一个国内的服务器
安装screen
为了保证关掉与服务器交互的窗口后仍然在运行,因此需要安装screen,直接运行
apt install screen
拉取镜像并关闭反作弊
pull镜像
docker pull aeonlucid/impostor
反作弊配置文件在app/config.json中,因此执行
find /var/lib/docker -name "config.json"
直接用vim修改config.json(每个人的那串id是不一样的)
vim /var/lib/docker/overlay2/7c6397c1e7d2fa13e0a65add69f7401576512b2a523b1a0ecaf9f61f4f970c2b/diff/app/config.json
将两处的true都改成false,如图
然后按下esc,:wq保存退出
运行docker
首先创建一个新的窗口,命名为au
screen -S au
接下来看一下刚刚pull的docker
docker images
然后开放指定端口,执行该命令
docker run -p 22023:22023/udp b96
导入配置文件
打开https://impostor.github.io/Impostor/
在server address里输入自己的服务器ip,在server name处输入你想命的名字
然后下载文件,将如果命名后有(1)等字样,请去掉,保证文件名为"regionInfo.json",不能错字 少字。
如果打不开上面的网站去下载文件,请将最后一行的xxx改成自己的IP与名字,完事后保存为regionInfo.json
{"CurrentRegionIdx":3,"Regions":[{"$type":"DnsRegionInfo, Assembly-CSharp","Fqdn":"na.mm.among.us","DefaultIp":"50.116.1.42","Port":22023,"Name":"North America","TranslateName":289,"UseDtls":true},{"$type":"DnsRegionInfo, Assembly-CSharp","Fqdn":"eu.mm.among.us","DefaultIp":"172.105.251.170","Port":22023,"Name":"Europe","TranslateName":290,"UseDtls":true},{"$type":"DnsRegionInfo, Assembly-CSharp","Fqdn":"as.mm.among.us","DefaultIp":"139.162.111.196","Port":22023,"Name":"Asia","TranslateName":291,"UseDtls":true},{"$type":"DnsRegionInfo, Assembly-CSharp","Fqdn":"xxx.xxx.xxx.xxx(IP)","DefaultIp":"xxx.xxx.xxx.xxx(IP)","Port":22023,"Name":"xxxxxxx(name)","TranslateName":1003,"UseDtls":false}]}
然后按下win+r,输入%APPDATA%\..\LocalLow\Innersloth\Among Us
后按下enter
直接替换掉下面的regionInfo.json
接下来即可关掉与服务器交互的窗口,并打开游戏选择自己的服务器。
如果要回到之前的au窗口,只需要输入
screen -R au
mod问题
在玩mod的时候(如LMv),可能会在创建房间时出现下面这个问题
服务器没有响应握手。
解决方法是修改游戏目录下的BepInEx\config\gg.reactor.api.cfg文件,将Allow vanilla servers = false
改成Allow vanilla servers = ture
(允许普通服务器)
如果是玩多模,还是推荐GM(
顺便发现GMHv2.1.58里面,在BepInEx下有个日志(LogOutput.log)
测试了一下是实时更新的,草
游戏内语音(BetterCrewLink)
可在github官网进行下载https://github.com/OhMyGuus/BetterCrewLink/releases
但是官网的会强制更新,所以推荐到四个HP汉化组去下载2.9.7汉化去更新版本
https://amonguscn.club/近距离语音模组better-crewlink汉化/
下载安装到任意盘后直接打开
当游戏启动后则进入等待页面,此时大家都进入同一房间后将会自动连上语音软件。可在主界面对不同的玩家音量进行调整,在设置里面也能对总音量进行调整。
对于语音软件的设置,每次开房间的房主可进行设置,其他玩家的设置将会失效并跟随房主的设置。
默认使用的是一个国外服务器,如果要使用自己的服务器。可执行如下命令
创建窗口
screen -R au2
拉取docker镜像(其中第一个9736可修改为其他端口)
docker run -d -p 9736:9736 ohmyguus/bettercrewlink-server:latest
在软件中找到高级设置,修改语音服务器,修改为http://你的ip:你的端口
然后打开NAT修复即可
有时候会出现有些人能用 有些不能用的情况,暂时还没搞明白为什么。
GMH汉化日志分析-Python
没事干写的,还有点问题,可以先测试用,没有优化过,脚本存在奇怪问题概率感觉比较大(因为手里中立获胜日志太少只能凭感觉写没法验证)
然后对于船员、狐妖、豺狼和内鬼的判定,都可以写成如同中立的判定改为循环
但是脚本里的阵营判定是一个个写的暂时不是很想改(能实现功能就是成功!)
想修改的可以自行修改
日志文件在Among Us GMHv2.1.58\BepInEx\LogOutput.log
(对于空数组没有做try-except,即如果有人没有赢过就会报错,这个问题 还没修)
2022/9/1修复起诉人重复胜利问题
2022/9/5修复律师代替胜利但不增加获胜次数问题
2022/9/19增加职业每把显示与获胜显示(在游戏开始时不能退出否则从那把开始后面数据混乱,这个问题暂时不想修)
2023/2/4修改新版起诉人问题,新增总被刀次数与总投票次数,未增加魅魔、丘比特职业判定,增加福尔摩斯职业判定
(括号内为前职业)
# -*- codeing = utf-8 -*-
# @Time : 2022/9/19 11:38
# @Author : Mumuzi
# @File : win_pro.py
# @Software : PyCharm
import re
from collections import Counter
from tabulate import tabulate
Impostor = ['内鬼','黑手党','化形者','隐蔽者','邪恶的黑客','吸血鬼','抹除者','骗术师','清理者','术士','赏金猎人','女巫','刺客','忍者','嗜血杀手','设陷者','双子爆破者','邪恶的追踪者','模仿者','复仇者','邪恶的赌怪','邪恶的换票师','背叛的','骇客']
Crewmate = ['船员','占卜师','市长','工程师','警长','执灯人','侦探','时间之主','医生','灵媒','黑客','追踪者','告密者','卧底','保安','诱饵','通灵师','正义的赌怪','正义的换票师','福尔摩斯']
Neutral_Win = ['黑死病','夜晚的黑暗是那么惹人怜爱','你们都是我的傀儡','小丑竟是我自己','用火焰净化一切','多谢款待','打赢官司']
Neutral_Name = ['疫医','化身博士','傀儡','小丑','纵火犯','秃鹫','律师','连环交换师','薛定谔的猫','豺狼','跟班','狐妖','背德者']
def Collect_Winner():
ind = []
for i in range(len(f)):
if('Game Result' in f[i]):
ind.append(i)
return ind
def Collect_Role():
ind = []
for i in range(len(f)):
if('Role Assign' in f[i]):
ind.append(i)
return ind
def Check_Main_User():
for i in range(len(f)):
if('[Settings][*]' in f[i]):
name = re.search(':(.*):', f[i][40:]).group(0)[1:-1].strip()
return name
def Get_ind_AND_NS(Name,Win_Times,ind,HuaiBi):
ind2 = ind
while True:
if ('--------------------------------' not in f[ind2]):
ind2 += 1
else:
break
for i in range(ind + 1, ind2):
try:
name = re.search('\[Result\](.*?)<{1}', f[i]).group(0)[8:-1]
except:
pass
if (name not in Name):
Name.append(name)
Win_Times.append(0)
HuaiBi.append([])
return Name,Win_Times,ind2,HuaiBi
def Check_Winner(Name,Win_Times,ind,Muser,HuaiBi,FTWIN):
Follow = True #已经忘了为啥要写Follow=True,但是不想进行修改
Lawyer,Lawyer_Muser = False,False
inds = ind-1
while True:
if('[Result]' in f[inds]):
role_win = f[inds]
break
else:
inds -= 1
if(('律师取代客户获得胜利' in f[ind-1]) or ('律师随客户一同胜利' in f[ind-1])):
Lawyer,Lawyer_Muser = True,True #主机作为客户时无§标志
# print(role_win)
Name, Win_Times, ind2,HuaiBi = Get_ind_AND_NS(Name, Win_Times, ind,HuaiBi)
FTWin = [False] * len(Name)
for _ in range(ind+1,ind2):
if('律师' in f[_]):
rep_name = re.search('\[Result\](.*?)<{1}', f[_]).group(0)[8:-1]
break
if('豺狼' in role_win):
for i in range(ind + 1, ind2):
if(('豺狼' in f[i]) or ('跟班' in f[i])):
try:
name = re.search('\[Result\](.*?)<{1}', f[i]).group(0)[8:-1]
if ((Lawyer == True) and ('§' in f[i])):
name = rep_name
Lawyer,Lawyer_Muser = False,False
Win_Times[Name.index(name)] += 1
FTWin[Name.index(name)] = True
HuaiBi[Name.index(name)].append('豺狼阵营胜利')
except:
pass
if(Lawyer == True):
Win_Times[Name.index(rep_name)] += 1
Win_Times[Name.index(Muser)] -= 1
FTWin[Name.index(rep_name)] = True
FTWin[Name.index(Muser)] = False
HuaiBi[Name.index(rep_name)].append('豺狼阵营胜利')
elif('小丑' in role_win):
for i in range(ind + 1, ind2):
if('小丑' in f[i]):
try:
name = re.search('\[Result\](.*?)<{1}', f[i]).group(0)[8:-1]
if ((Lawyer == True) and ('§' in f[i])):
name = rep_name
Lawyer,Lawyer_Muser = False,False
Win_Times[Name.index(name)] += 1
FTWin[Name.index(name)] = True
HuaiBi[Name.index(name)].append('其他中立阵营胜利')
except:
pass
if(Lawyer == True):
Win_Times[Name.index(rep_name)] += 1
Win_Times[Name.index(Muser)] -= 1
FTWin[Name.index(rep_name)] = True
FTWin[Name.index(Muser)] = False
HuaiBi[Name.index(rep_name)].append('其他中立阵营胜利')
elif('jekyllAndHydeWinExtra' in role_win):
for i in range(ind + 1, ind2):
if('化身' in f[i]):
try:
Lawyer, Lawyer_Muser = False, False
name = re.search('\[Result\](.*?)<{1}', f[i]).group(0)[8:-1]
Win_Times[Name.index(name)] += 1
FTWin[Name.index(name)] = True
HuaiBi[Name.index(name)].append('其他中立阵营胜利')
break
except:
pass
elif('船员' in role_win and '迷你' not in role_win):
for i in range(ind + 1, ind2):
for j in Crewmate:
if(j in f[i]):
if(('背叛' not in f[i])):
try:
name = re.search('\[Result\](.*?)<{1}', f[i]).group(0)[8:-1]
if ((Lawyer == True) and ('§' in f[i])):
name = rep_name
Lawyer, Lawyer_Muser = False, False
Win_Times[Name.index(name)] += 1
FTWin[Name.index(name)] = True
HuaiBi[Name.index(name)].append('船员阵营胜利')
break
except:
pass
if(Lawyer == True):
Win_Times[Name.index(rep_name)] += 1
Win_Times[Name.index(Muser)] -= 1
FTWin[Name.index(rep_name)] = True
FTWin[Name.index(Muser)] = False
HuaiBi[Name.index(rep_name)].append('船员阵营胜利')
elif('恋人' in role_win):
for i in range(ind + 1, ind2):
if(('♥' in f[i]) or ('背叛' in f[i])):
try:
name = re.search('\[Result\](.*?)<{1}', f[i]).group(0)[8:-1]
if ((Lawyer == True) and ('§' in f[i])):
name = rep_name
Lawyer, Lawyer_Muser = False, False
Win_Times[Name.index(name)] += 1
FTWin[Name.index(name)] = True
HuaiBi[Name.index(name)].append('恋人阵营胜利')
except:
pass
if(Lawyer == True):
Win_Times[Name.index(rep_name)] += 1
Win_Times[Name.index(Muser)] -= 1
FTWin[Name.index(rep_name)] = True
FTWin[Name.index(Muser)] = False
HuaiBi[Name.index(rep_name)].append('恋人阵营胜利')
elif('内鬼' in role_win):
for i in range(ind + 1,ind2):
for j in Impostor:
if(j in f[i]):
try:
name = re.search('\[Result\](.*?)<{1}', f[i]).group(0)[8:-1]
if ((Lawyer == True) and ('§' in f[i])):
name = rep_name
Lawyer, Lawyer_Muser = False, False
Win_Times[Name.index(name)] += 1
FTWin[Name.index(name)] = True
HuaiBi[Name.index(name)].append('内鬼阵营胜利')
break
except:
pass
if(Lawyer == True):
Win_Times[Name.index(rep_name)] += 1
Win_Times[Name.index(Muser)] -= 1
FTWin[Name.index(rep_name)] = True
FTWin[Name.index(Muser)] = False
HuaiBi[Name.index(rep_name)].append('内鬼阵营胜利')
elif('狐妖' in role_win):
for i in range(ind + 1, ind2):
if(('狐妖' in f[i]) or ('背德者' in f[i])):
try:
name = re.search('\[Result\](.*?)<{1}', f[i]).group(0)[8:-1]
if ((Lawyer == True) and ('§' in f[i])):
name = rep_name
Lawyer,Lawyer_Muser = False,False
Win_Times[Name.index(name)] += 1
FTWin[Name.index(name)] = True
HuaiBi[Name.index(name)].append('狐妖阵营胜利')
except:
pass
if(Lawyer == True):
Win_Times[Name.index(rep_name)] += 1
Win_Times[Name.index(Muser)] -= 1
FTWin[Name.index(rep_name)] = True
FTWin[Name.index(Muser)] = False
HuaiBi[Name.index(rep_name)].append('狐妖阵营胜利')
else:
for Ne in Neutral_Win:
if(Ne in role_win):
for i in range(ind + 1, ind2):
if (Neutral_Name[Neutral_Win.index(Ne)] in f[i]):
try:
name = re.search('\[Result\](.*?)<{1}', f[i]).group(0)[8:-1]
if ((Lawyer == True) and ('§' in f[i])):
name = rep_name
Lawyer, Lawyer_Muser = False, False
Win_Times[Name.index(name)] += 1
FTWin[Name.index(name)] = True
HuaiBi[Name.index(name)].append('其他中立阵营胜利')
break
except:
pass
if (Lawyer == True):
Win_Times[Name.index(rep_name)] += 1
Win_Times[Name.index(Muser)] -= 1
FTWin[Name.index(rep_name)] = True
FTWin[Name.index(Muser)] = False
HuaiBi[Name.index(rep_name)].append('其他中立阵营胜利')
break
if(Follow == True): #忘了写这个判断是图啥的来着
for i in range(ind+1,ind2):
LIFE = re.search('<pos=25%>(.*)<pos=34%>',f[i]).group(0)[9:-9]
if((('投机者' in f[i]) or ('起诉人' in f[i])) and (LIFE == '存活')):
name = re.search('\[Result\](.*?)<{1}', f[i]).group(0)[8:-1]
Win_Times[Name.index(name)] += 1
FTWin[Name.index(name)] = True
if('狐妖' in role_win):
HuaiBi[Name.index(name)].append('狐妖阵营胜利')
elif('内鬼' in role_win):
HuaiBi[Name.index(name)].append('内鬼阵营胜利')
elif('豺狼' in role_win):
HuaiBi[Name.index(name)].append('豺狼阵营胜利')
elif('船员' in role_win):
HuaiBi[Name.index(name)].append('船员阵营胜利')
elif ('恋人' in role_win):
HuaiBi[Name.index(name)].append('恋人阵营胜利')
else:
HuaiBi[Name.index(name)].append('其他中立阵营胜利')
break
Role = ['']*len(Name)
for i in range(ind+1,ind2):
Temp = ''
for _ in Impostor:
if(_ in f[i]):
Temp = _
break
for _ in Crewmate:
if(_ in f[i]):
if('背叛' in f[i]):
Temp = f'背叛的{_}'
break
else:
Temp = _
for _ in Neutral_Name:
if(_ in f[i]):
Temp = _
break
if('投机者' in f[i]):
Temp = '投机者'
if('起诉人' in f[i]):
Temp = '起诉人'
if('♥' in f[i]):
Temp += ' + 恋人'
name = re.search('\[Result\](.*?)<{1}', f[i]).group(0)[8:-1]
Role[Name.index(name)] = Temp
FTWIN.append(FTWin)
# print(Name, Win_Times, len(HuaiBi[3]), FTWIN)
return Name,Win_Times,HuaiBi,FTWIN,Role
def Get_Every_Occ(Name,ind,occ,Winner,Last_Role):
Temp = ['-']*len(Name)
for i in range(ind,len(f)):
if('------Platforms-------' in f[i]):
ind2 = i
break
for i in range(ind+1,ind2):
try:
name = re.search('\[Settings\][ \[\]0-9](.*)[ ]:',f[i]).group(0)[16:-1].strip()
Duty = re.search(':(.*)',f[i][f[i].index(name):]).group(0)[1:]
ind_role = Name.index(name)
if(Duty == Last_Role[ind_role]):
if(Winner[ind_role] == True):
Temp[ind_role] = f'\033[32m{Duty}\033[0m'
else:
Temp[ind_role] = Duty
else:
if(Winner[ind_role] == True):
Temp[ind_role] = f'\033[32m{Last_Role[ind_role]}({Duty})\033[0m'
else:
Temp[ind_role] = f'{Last_Role[ind_role]}({Duty})'
except:
pass
occ.append(Temp)
return occ
def Count_Max_Teamer(User,HuaiBi):
Max = []
for i in range(len(HuaiBi)):
print(User[i],HuaiBi[i])
try:
Max.append(Counter(HuaiBi[i]).most_common()[0][0])
except:
Max.append([])
return Max
def GG_First(User,ind):
GG = []
ind.insert(0,0)
for _ in range(len(User)):
GG.append(0)
for i in range(len(ind)-1):
for j in range(ind[i],ind[i+1]):
if('[MurderPlayer]' in f[j]):
NAME = re.search('=> (.*)\(',f[j]).group(0)[3:-1]
if(NAME not in User):
pass
else:
GG[User.index(NAME)] += 1
break
# print(Counter(dict(zip(User,GG))).most_common())
GG_MAX,GG_Min = Counter(dict(zip(User,GG))).most_common()[0],Counter(dict(zip(User,GG))).most_common()[-1]
return GG_MAX,GG_Min
def Vote_First(User,ind):
Vote = []
ind.insert(0,0)
for _ in range(len(User)):
Vote.append(0)
for i in range(len(ind)-1):
for j in range(ind[i],ind[i+1]):
try:
if('[Vote]' in f[j]):
NAME = re.search('Exiled: (.*)\((.*)\(',f[j]).group(2)
if(NAME not in User):
pass
else:
Vote[User.index(NAME)] += 1
break
except:
pass
# print(Counter(dict(zip(User, Vote))).most_common())
Vote_MAX, Vote_Min = Counter(dict(zip(User, Vote))).most_common()[0], Counter(dict(zip(User, Vote))).most_common()[-1]
return Vote_MAX,Vote_Min
def Get_StartTime_EndTime():
for i in range(len(f)):
if('[Info :The Other Roles GM]' in f[i]):
Start = re.search('GM\] \[(.*)\]\[',f[i]).group(0)[5:-2]
break
for i in range(len(f)-1,-1,-1):
if('[Info :The Other Roles GM]' in f[i]):
End = re.search('GM\] \[(.*)\]\[',f[i]).group(0)[5:-2]
break
return Start,End
def SHOW(Name,Occ):
Occ.insert(0,Name)
Sol = tabulate(Occ, headers='firstrow', tablefmt='grid')
print(Sol)
def GG_All(User):
GG = []
for _ in range(len(User)):
GG.append(0)
for i in range(len(f)):
if('[MurderPlayer]' in f[i]):
NAME = re.search('=> (.*)\(',f[i]).group(0)[3:-1]
if(NAME not in User):
pass
else:
GG[User.index(NAME)] += 1
# print(Counter(dict(zip(User,GG))).most_common())
# GG_MAX,GG_Min = Counter(dict(zip(User,GG))).most_common()[0],Counter(dict(zip(User,GG))).most_common()[-1]
GG_a = str(Counter(dict(zip(User,GG))))[9:-2]
return GG_a
def Vote_All(User):
Vote = []
for _ in range(len(User)):
Vote.append(0)
for i in range(len(f)):
try:
if('[Vote]' in f[i]):
NAME = re.search('Exiled: (.*)\((.*)\(',f[i]).group(2)
if(NAME not in User):
pass
else:
Vote[User.index(NAME)] += 1
except:
pass
# print(Counter(dict(zip(User, Vote))).most_common())
Vote_a = str(Counter(dict(zip(User,Vote))))[9:-2]
# Vote_MAX, Vote_Min = Counter(dict(zip(User, Vote))).most_common()[0], Counter(dict(zip(User, Vote))).most_common()[-1]
return Vote_a
if __name__ == "__main__":
f = open('LogOutput.log','r',encoding='utf-8').read().splitlines() #日志位置
Start_Time,End_Time = Get_StartTime_EndTime()
Winner_index,Roles = Collect_Winner(),Collect_Role() #len(Winner_index) = turns
User_Name,Winner_Times,HuaiBi,Occ,Role_Win,FTWin = [],[],[],[],[],[]
Main_User = Check_Main_User()
for i in range(len(Winner_index)):
User_Name, Winner_Times,HuaiBi,FTWin,ACC_Role = Check_Winner(User_Name,Winner_Times,Winner_index[i],Main_User,HuaiBi,FTWin)
Occ = Get_Every_Occ(User_Name, Roles[i],Occ,FTWin[i],ACC_Role) #Roles->开始的职业,ACC_Role->结束的职业
Score = dict(zip(User_Name,HuaiBi))
Score = dict(sorted(Score.items(),key=lambda x:len(x[1]))[::-1])
Max_HuaiBi = Count_Max_Teamer(User_Name,HuaiBi)
SHOW(User_Name,Occ)
print(f'[统计信息]本地资源分析:从{Start_Time}到{End_Time}期间共开始了{len(Winner_index)}场游戏\n获胜ID从高到低依次为:')
for i,j in Score.items():
if(len(j)!=0):
print(f'{i} 共获胜{len(j)}场'.ljust(15),f'其中作为{Max_HuaiBi[User_Name.index(i)]}次数最多'.ljust(20))
else:
print(f'{i} 共获胜{len(j)}场 乐'.ljust(15))
Max_GG,Min_GG = GG_First(User_Name,Winner_index)
Max_Vote,Min_Vote = Vote_First(User_Name,Winner_index)
GG_A,Vote_A = GG_All(User_Name),Vote_All(User_Name)
print(f'其中被首刀最多的是 {Max_GG[0]},共被首刀了{Max_GG[1]}次')
print(f'被首刀最少的是 {Min_GG[0]},仅被首刀了{Min_GG[1]}次')
print(f'其中被首投最多的是 {Max_Vote[0]},共被投了{Max_Vote[1]}次')
print(f'被首投最少的是 {Min_Vote[0]},仅被投了{Min_Vote[1]}次')
print(f'玩家被刀总次数如下:{GG_A}')
print(f'玩家被投总次数如下:{Vote_A}')