Skip to content

Commit ba64402

Browse files
authored
Merge pull request #116 from xBoyMinemc/每个玩家享受单独的假人额度(目前5)
每个玩家享受单独的假人额度(目前5)
2 parents de0843f + d6058b1 commit ba64402

8 files changed

Lines changed: 148 additions & 86 deletions

File tree

README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,6 @@
110110

111111
## 开发者信息 (Developer Info)
112112

113-
### TODO List
114-
- [ ] 编写测试用例
115-
- [ ] 开发一个基础的 UI 界面
116-
- [ ] 重构构建系统https://github.com/xBoyMinemc/FlashFakePlayerPack/pull/110
117-
118113
### 打包与发布流程
119114
1. 创建并推送一个新 tag,tag 名称以 `v` 开头(如 `v1.0.0`),这会通过 GitHub Actions 自动触发发布流程。
120115
2. 流程会执行以下步骤:

pack_icon.png

-453 Bytes
Binary file not shown.

packer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ const archive = archiver('zip', {
6464

6565
// 如果你想要在ZIP文件中添加多个文件,可以多次调用append方法
6666
archive.append(fs.createReadStream('manifest.json'), { name: 'manifest.json' });
67-
archive.append(fs.createReadStream('pack_icon.png'), { name: 'pack_icon.png' });
67+
// archive.append(fs.createReadStream('pack_icon.png'), { name: 'pack_icon.png' });
6868
// 使用directory方法添加整个目录到ZIP文件中
6969
['structures','entities','scripts/main'].forEach(_=>archive.directory(_, true)); // 第二个参数设置为false表示不包含目录本身
7070

tscripts/xTerrain/main.ts

Lines changed: 116 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type {
55
spawnedEvent,
66
spawnedEventSignal,
77
} from '../@types/globalThis'
8-
import {Dimension, LocationOutOfWorldBoundariesError, system, Vector3} from '@minecraft/server'
8+
import { Dimension, LocationOutOfWorldBoundariesError, Player, system, Vector3 } from '@minecraft/server'
99

1010
import { register } from '@minecraft/server-gametest'
1111

@@ -30,23 +30,23 @@ import './plugins/task'
3030
import './plugins/gui'
3131
import './plugins/autoFishing'
3232
import './plugins/killedBySimPlayer'
33-
import './plugins/setting'
33+
// import './plugins/setting'
3434
import './plugins/showCommandsList'
35-
import {playerMove} from "../lib/xboyEvents/move";
35+
import { playerMove } from "../lib/xboyEvents/move";
3636
import { cannotHandledExceptionWarningText, CommandError, commandManager, getLocationFromEntityLike } from '../lib/yumeCommand/CommandRegistry';
3737
import '../lib/yumeCommand/scriptEventHandler'
3838

3939
const overworld = world.getDimension('overworld')
40-
const tickWaitTimes = 20*60*60*24*365
40+
const tickWaitTimes = 20 * 60 * 60 * 24 * 365
41+
const max_simulatedPlayerCount = 5
4142
// all of SimulatedPlayer List
42-
export const simulatedPlayers = {}
43+
export const simulatedPlayers = {}
4344

4445
// simulatedPlayers[PID] = simulatedPlayer;
4546
// simulatedPlayers[simulatedPlayer.id] = PID;
4647

4748
export let initSucceed = false
4849

49-
5050
let randomTickSpeed = 1
5151
let doDayLightCycle = true
5252
let doMobSpawning = true
@@ -55,51 +55,119 @@ let doMobSpawning = true
5555

5656
randomTickSpeed = world.gameRules.randomTickSpeed
5757
doDayLightCycle = world.gameRules.doDayLightCycle
58-
doMobSpawning = world.gameRules.doMobSpawning
58+
doMobSpawning = world.gameRules.doMobSpawning
5959

60-
world.sendMessage('[模拟玩家] 随机刻->'+randomTickSpeed+'时间->'+doDayLightCycle+'生物生成->'+doMobSpawning)
60+
world.sendMessage('[模拟玩家] 随机刻->' + randomTickSpeed + '时间->' + doDayLightCycle + '生物生成->' + doMobSpawning)
6161
}
6262
// ?
6363

64-
let spawnSimulatedPlayer : (location:Vector3, dimension:Dimension, pid: number )=>SimulatedPlayer
65-
let spawnSimulatedPlayerByNameTag : (location:Vector3, dimension:Dimension, nameTag: string )=>SimulatedPlayer
66-
let testWorldLocation : Vector3
67-
let testWorldDimension : Dimension
64+
let spawnSimulatedPlayerByNameTag: (location: Vector3, dimension: Dimension, nameTag: string) => SimulatedPlayer
65+
let testWorldLocation: Vector3
66+
let testWorldDimension: Dimension
67+
68+
69+
if (!world.structureManager.get('xboyMinemcSIM:void'))
70+
world.structureManager.createEmpty('xboyMinemcSIM:void', { x: 1, y: 1, z: 1 }).saveToWorld()
71+
72+
const GetGlobalPID = () => world.scoreboard.getObjective('##FlashPlayer##').addScore('##currentPID', 1)
73+
74+
// 新增每个玩家的个人假人控制ID
75+
// 使用一个动态属性来管理每个玩家的个人假人控制ID
76+
// 为了一致所以暂不全部迁移到动态属性
77+
const currentPID4EveryPlayer = new Map<string, number>()
78+
const GetCurrentPID4Player = (playerId: string): number | null => {
79+
const _max_simulatedPlayerCount = GetPlayerSimulatedPlayerCount(playerId)
80+
if (_max_simulatedPlayerCount <= 0) return null
81+
const value = currentPID4EveryPlayer.get(playerId) ?? 0
82+
83+
// 获取此玩家当前可用假人数量
84+
const valid_CurrentPID_List = []
85+
for (let i = 1; i <= _max_simulatedPlayerCount; i++) {
86+
const PID = GetPlayerPID2GlobalPID(playerId, i)
87+
if (!PID) { valid_CurrentPID_List.push(i); continue }
88+
if (!simulatedPlayers[PID]?.isValid) { valid_CurrentPID_List.push(i); continue }
89+
}
90+
91+
92+
if (valid_CurrentPID_List.length <= 0) return null
93+
return currentPID4EveryPlayer.set(playerId, value + 1).get(playerId)
94+
}
95+
// 将这个这个每次重启游戏重置为1的玩家假人PID和全局递增PID挂钩并且存储在动态属性以供持久化假人信息
96+
// 每次玩家请求一个假人都会分配一个玩家个人假人PID
97+
// 如果查询到这个玩家的个人假人PID和全局挂钩则将此个人假人PID指向此全局PID以关联持久化信息
98+
// 否则获取一个新的全局PID关联到此假人并且存储到动态属性
99+
// simulatedPlayers中依旧使用全局PID
100+
function SetPlayerPID2GlobalPID(playerId: string, CurrentPID4Player: number, GlobalPID: number) {
101+
// const ex = {
102+
// "-56789": {
103+
// "GlobalPID": 1234567890
104+
// }
105+
// }
106+
// 苦一苦存储,骂名我来担
107+
let data = <string>world.getDynamicProperty("info4EveryPlayer_" + playerId) ?? "{}"
108+
const dataObject = JSON.parse(data)
109+
if (!dataObject[CurrentPID4Player])
110+
dataObject[CurrentPID4Player] = {}
111+
dataObject[CurrentPID4Player]["GlobalPID"] = GlobalPID
112+
data = JSON.stringify(dataObject)
113+
world.setDynamicProperty("info4EveryPlayer_" + playerId, data)
114+
}
115+
const GetPlayerPID2GlobalPID = (playerId: string, CurrentPID4Player: number): number => {
116+
const data = <string>world.getDynamicProperty("info4EveryPlayer_" + playerId) ?? "{}"
117+
const dataObject = JSON.parse(data)
118+
let GlobalPID = dataObject?.[CurrentPID4Player]?.GlobalPID
119+
if (!GlobalPID)
120+
SetPlayerPID2GlobalPID(playerId, CurrentPID4Player, GlobalPID = GetGlobalPID())
121+
return GlobalPID as number
122+
}
68123

124+
// 每个玩家享受单独的假人限额
125+
const GetPlayerSimulatedPlayerCount = (playerId: string): number => {
126+
const data = <string>world.getDynamicProperty("info4EveryPlayer_" + playerId) ?? "{}"
127+
const dataObject = JSON.parse(data)
128+
let _max_simulatedPlayerCount = dataObject?._max_simulatedPlayerCount
129+
if (!_max_simulatedPlayerCount) {
130+
_max_simulatedPlayerCount = max_simulatedPlayerCount
131+
SetPlayerSimulatedPlayerCount(playerId, _max_simulatedPlayerCount)
132+
world.sendMessage('[模拟玩家] 每个玩家享受单独的假人限额: ' + _max_simulatedPlayerCount)
133+
}
134+
return _max_simulatedPlayerCount as number
135+
}
69136

70-
if(!world.structureManager.get('xboyMinemcSIM:void'))
71-
world.structureManager.createEmpty('xboyMinemcSIM:void', { x:1, y:1, z:1 }).saveToWorld()
137+
const SetPlayerSimulatedPlayerCount = (playerId: string, count: number) => {
138+
let data = <string>world.getDynamicProperty("info4EveryPlayer_" + playerId) ?? "{}"
139+
const dataObject = JSON.parse(data)
140+
dataObject._max_simulatedPlayerCount = count
141+
data = JSON.stringify(dataObject)
142+
world.setDynamicProperty("info4EveryPlayer_" + playerId, data)
143+
}
72144

73-
let currentPID = 0
74-
const GetPID = ()=> ++currentPID
75145

76146

77-
export const initialized : initializedEventSignal = new EventSignal<initializedEvent>()
78-
export const spawned : spawnedEventSignal = new EventSignal<spawnedEvent>()
147+
export const initialized: initializedEventSignal = new EventSignal<initializedEvent>()
148+
export const spawned: spawnedEventSignal = new EventSignal<spawnedEvent>()
79149

80-
register('我是云梦', '假人', (test:Test) => {
81-
testWorldLocation = test.worldBlockLocation({ x:0, y:0, z:0 })
82-
testWorldLocation["worldBlockLocation"] = (v3:Vector3)=> test.worldBlockLocation(v3)
150+
register('我是云梦', '假人', (test: Test) => {
151+
testWorldLocation = test.worldBlockLocation({ x: 0, y: 0, z: 0 })
152+
testWorldLocation["worldBlockLocation"] = (v3: Vector3) => test.worldBlockLocation(v3)
83153

84154

85155
world.gameRules.randomTickSpeed = randomTickSpeed
86156
world.gameRules.doDayLightCycle = doDayLightCycle
87157
world.gameRules.doMobSpawning = doMobSpawning
88158

89-
spawnSimulatedPlayer = (location:Vector3, dimension:Dimension, pid: number ):SimulatedPlayer=>{
90-
return spawnSimulatedPlayerByNameTag(location, dimension, `工具人-${pid}`)
91-
}
92-
spawnSimulatedPlayerByNameTag = (location:Vector3, dimension:Dimension, nameTag: string ):SimulatedPlayer=>{
159+
spawnSimulatedPlayerByNameTag = (location: Vector3, dimension: Dimension, nameTag: string): SimulatedPlayer => {
93160

94-
const simulatedPlayer = test.spawnSimulatedPlayer({ x:0, y:8, z:0 }, nameTag)
161+
// 是的,这个nameTag在这里实际先被作为name
162+
const simulatedPlayer = test.spawnSimulatedPlayer({ x: 0, y: 8, z: 0 }, nameTag)
95163
simulatedPlayer.addTag('Backpack2Barrel_init')
96164
simulatedPlayer.addTag(SIGN.YUME_SIM_SIGN)
97165
simulatedPlayer.addTag(SIGN.AUTO_RESPAWN_SIGN)
98166
try {
99167
//@ts-ignore
100-
simulatedPlayer.setSpawnPoint({...location, dimension})
168+
simulatedPlayer.setSpawnPoint({ ...location, dimension })
101169
//@ts-ignore
102-
simulatedPlayer.teleport(location, {dimension})
170+
simulatedPlayer.teleport(location, { dimension })
103171
} catch (e) {
104172
if (e instanceof LocationOutOfWorldBoundariesError) {
105173
console.warn('[模拟玩家] 有东西尝试在非法位置生成假人,已阻止');
@@ -116,59 +184,40 @@ register('我是云梦', '假人', (test:Test) => {
116184
initSucceed = true
117185
console.log('[模拟玩家] 初始化完成,输入“假人创建”或“ffpp”')
118186
})
119-
.maxTicks(tickWaitTimes)
120-
.structureName('xboyMinemcSIM:void');
187+
.maxTicks(tickWaitTimes)
188+
.structureName('xboyMinemcSIM:void');
121189
// .maxTicks(2)
122190
// .maxAttempts(tickWaitTimes)
123191
// .requiredSuccessfulAttempts(tickWaitTimes)
124192
// .padding(0)
125193

126-
// 记分板PID初始化 写的烂 执行两次
127-
verify()
128-
verify()
129-
130-
let z = 11451400 + Math.floor(Math.random() * 114514 * 19 )
131-
z -= z%16
132-
system.run(()=>{
133-
try {
134-
overworld.runCommand('execute positioned 15000000 256 ' + z + ' run gametest run 我是云梦:假人');
135-
testWorldDimension = overworld
136-
} catch (e) {
137-
world.sendMessage('[模拟玩家] 报错了,我也不知道为什么' + e);
138-
}
139-
});
194+
// 记分板PID初始化 写的烂 执行两次
195+
verify()
196+
verify()
197+
198+
let z = 11451400 + Math.floor(Math.random() * 114514 * 19)
199+
z -= z % 16
200+
system.run(() => {
201+
try {
202+
overworld.runCommand('execute positioned 15000000 256 ' + z + ' run gametest run 我是云梦:假人');
203+
testWorldDimension = overworld
204+
} catch (e) {
205+
world.sendMessage('[模拟玩家] 报错了,我也不知道为什么' + e);
206+
}
207+
});
140208

141209

142210
let say = false
143-
playerMove.subscribe(()=>{
211+
playerMove.subscribe(() => {
144212
if (say) return
145213
say = true
146214
world.sendMessage('[模拟玩家] 初始化完成,输入“假人创建”或“ffpp”')
147215
//添加第二行提示
148216
world.sendMessage('[模拟玩家] 输入“假人帮助”以获取使用说明')
149217
})
150218

151-
// initialized.subscribe(()=> console.error('[模拟玩家]初始化完毕,加载内置插件') )
152-
// initialized.subscribe(()=>
153-
// {
154-
// }
155-
// // 'test',
156-
// // 'chatSpawn',
157-
// // 'command',
158-
// // 'breakBlock',
159-
// // 'youAreMine',
160-
// // 'help',
161-
// // 'task',
162-
// // 'gui',
163-
// // 'autoFishing',
164-
// // 'killedBySimPlayer',
165-
// // 'setting',
166-
// // 'Deja Vu Yan Returns',
167-
// // '鱼肉 ‭‭‭⁧⁧⁧~咕噜咕噜',
168-
//
169-
// )
170-
171-
world.beforeEvents.chatSend.subscribe(({message, sender}) => {
219+
220+
world.beforeEvents.chatSend.subscribe(({ message, sender }) => {
172221
system.run(() => {
173222
try {
174223
commandManager.execute(message, {
@@ -185,5 +234,5 @@ world.beforeEvents.chatSend.subscribe(({message, sender}) => {
185234
});
186235
});
187236

188-
export { spawnSimulatedPlayer,spawnSimulatedPlayerByNameTag,testWorldLocation,testWorldDimension,GetPID }
237+
export { spawnSimulatedPlayerByNameTag, testWorldLocation, testWorldDimension, GetGlobalPID, GetCurrentPID4Player, GetPlayerPID2GlobalPID }
189238

tscripts/xTerrain/plugins/Backpack2Barrel.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ async function saveAllFakePlayerBackpack() {
117117
if (!_SimulatedPlayer.isValid) return
118118
const index = Number(PID) * 3
119119
if (index < 0) return
120-
let void_count = 0
120+
let void_count = 0 // 空缺的存储木桶数量
121121

122122
const location0 = addVector3(structure_location, indexToVector3(index + 0))
123123
const block_backpack = testWorldDimension.getBlock(location0)
@@ -163,7 +163,7 @@ async function saveAllFakePlayerBackpack() {
163163
})
164164

165165
_SimulatedPlayer.removeTag("Backpack2Barrel_init")
166-
world.sendMessage(`${_SimulatedPlayer.name} 背包还原成功`)
166+
world.sendMessage(`${_SimulatedPlayer.name} 背包还原->正常`)
167167
return
168168
}
169169

@@ -204,6 +204,18 @@ async function saveAllFakePlayerBackpack() {
204204

205205
}
206206

207+
export function getFakePlayerNameTag(PID: number):string | null {
208+
const index = Number(PID) * 3 + 1
209+
if (index < 0) return
210+
const location = addVector3(structure_location, indexToVector3(index))
211+
const block = testWorldDimension.getBlock(location)
212+
if (block.type.id !== VoidBarrel.id) {
213+
return null
214+
}
215+
const inv = block.getComponent("minecraft:inventory")
216+
const con = inv.container
217+
return con.getItem(15).nameTag
218+
}
207219

208220

209221
system.runInterval(async () => {
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
// 似曾相识燕归来
22

3-
3+
// 实际上这个空文件是当时为了实现保存和恢复假人信息而存在的

tscripts/xTerrain/plugins/chatSpawn.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import type {SimulatedPlayer} from '@minecraft/server-gametest'
22

33
import {
4-
GetPID, initSucceed,
4+
GetCurrentPID4Player,
5+
GetGlobalPID, GetPlayerPID2GlobalPID, initSucceed,
56
simulatedPlayers,
67
spawned as spawnedEvent,
7-
spawnSimulatedPlayer,
88
spawnSimulatedPlayerByNameTag
99
} from '../main'
1010
import { type CommandInfo, commandManager, Command } from '../../lib/yumeCommand/CommandRegistry'
1111
import { Dimension, Vector3, world, type Player } from '@minecraft/server'
1212
import {xyz_dododo} from "../../lib/xboyPackage/xyz_dododo";
13+
import { getFakePlayerNameTag } from './Backpack2Barrel';
1314

1415
const overworld = world.getDimension("overworld");
1516

@@ -19,18 +20,22 @@ const spawnAndRegisterSimulatedPlayer = (entity: Player | undefined, location: V
1920
return;
2021
}
2122

22-
const PID = GetPID();
23+
const PlayerPID = GetCurrentPID4Player(entity.id);
24+
if (!PlayerPID) {
25+
entity?.sendMessage('[模拟玩家] 假人数量已达上限,请删除假人后再试');
26+
return;
27+
}
28+
const GlobalPID = GetPlayerPID2GlobalPID(entity.id, PlayerPID);
29+
const name = getFakePlayerNameTag(GlobalPID) ?? nameTag ?? ((entity?.name ?? 'flash') + PlayerPID)
2330
const __FlashPlayer__ = world.scoreboard.getObjective('##FlashPlayer##');
24-
const simulatedPlayer: SimulatedPlayer = nameTag
25-
? spawnSimulatedPlayerByNameTag(location, dimension, nameTag)
26-
: spawnSimulatedPlayer(location, dimension, PID);
31+
const simulatedPlayer: SimulatedPlayer = spawnSimulatedPlayerByNameTag(location, dimension, name)
2732

2833

29-
simulatedPlayers[PID] = simulatedPlayer;
30-
simulatedPlayers[simulatedPlayer.id] = PID;
34+
simulatedPlayers[GlobalPID] = simulatedPlayer;
35+
simulatedPlayers[simulatedPlayer.id] = GlobalPID;
3136

32-
spawnedEvent.trigger({ spawnedSimulatedPlayer: simulatedPlayer, PID });
33-
__FlashPlayer__.setScore(simulatedPlayer.id, PID);
37+
spawnedEvent.trigger({ spawnedSimulatedPlayer: simulatedPlayer, PID:GlobalPID });
38+
__FlashPlayer__.setScore(simulatedPlayer.id, GlobalPID);
3439
};
3540

3641
const chatSpawnCommand = new Command();
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// 但是这个真的忘记是准备写什么了。

0 commit comments

Comments
 (0)