ScriptLib.java 16.6 KB
Newer Older
1
2
package emu.grasscutter.scripts;

Akka's avatar
Akka committed
3
import emu.grasscutter.game.dungeons.challenge.DungeonChallenge;
4
5
6
import emu.grasscutter.game.entity.EntityGadget;
import emu.grasscutter.game.entity.EntityMonster;
import emu.grasscutter.game.entity.GameEntity;
Melledy's avatar
Melledy committed
7
import emu.grasscutter.game.entity.gadget.GadgetWorktop;
Akka's avatar
Akka committed
8
import emu.grasscutter.game.dungeons.challenge.factory.ChallengeFactory;
Akka's avatar
Akka committed
9
10
11
import emu.grasscutter.game.props.EntityType;
import emu.grasscutter.game.quest.enums.QuestState;
import emu.grasscutter.game.quest.enums.QuestTrigger;
12
import emu.grasscutter.scripts.data.SceneGroup;
Melledy's avatar
Melledy committed
13
import emu.grasscutter.scripts.data.SceneRegion;
14
import emu.grasscutter.server.packet.send.PacketCanUseSkillNotify;
Akka's avatar
Akka committed
15
import emu.grasscutter.server.packet.send.PacketDungeonShowReminderNotify;
16
import emu.grasscutter.server.packet.send.PacketWorktopOptionNotify;
17
import io.netty.util.concurrent.FastThreadLocal;
18
19
20
21
22
23
import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Optional;
24
25

public class ScriptLib {
26
	public static final Logger logger = LoggerFactory.getLogger(ScriptLib.class);
27
28
29
30
31
32
33
34
35
36
37
38
39
	private final FastThreadLocal<SceneScriptManager> sceneScriptManager;
	private final FastThreadLocal<SceneGroup> currentGroup;
	public ScriptLib() {
		this.sceneScriptManager = new FastThreadLocal<>();
		this.currentGroup = new FastThreadLocal<>();
	}

	public void setSceneScriptManager(SceneScriptManager sceneScriptManager){
		this.sceneScriptManager.set(sceneScriptManager);
	}

	public void removeSceneScriptManager(){
		this.sceneScriptManager.remove();
40
41
42
	}

	public SceneScriptManager getSceneScriptManager() {
43
44
		// normally not null
		return Optional.of(sceneScriptManager.get()).get();
45
	}
46
47
48
49
50
51
52
53
54
55

	private String printTable(LuaTable table){
		StringBuilder sb = new StringBuilder();
		sb.append("{");
		for(var meta : table.keys()){
			sb.append(meta).append(":").append(table.get(meta)).append(",");
		}
		sb.append("}");
		return sb.toString();
	}
Akka's avatar
Akka committed
56
57
58
59
	public void setCurrentGroup(SceneGroup currentGroup){
		this.currentGroup.set(currentGroup);
	}
	public Optional<SceneGroup> getCurrentGroup(){
60
		return Optional.of(this.currentGroup.get());
Akka's avatar
Akka committed
61
62
63
64
	}
	public void removeCurrentGroup(){
		this.currentGroup.remove();
	}
65
	public int SetGadgetStateByConfigId(int configId, int gadgetState) {
66
67
		logger.debug("[LUA] Call SetGadgetStateByConfigId with {},{}",
				configId,gadgetState);
68
69
70
71
72
73
		Optional<GameEntity> entity = getSceneScriptManager().getScene().getEntities().values().stream()
				.filter(e -> e.getConfigId() == configId).findFirst();

		if (entity.isEmpty()) {
			return 1;
		}
Akka's avatar
Akka committed
74
75
76
77

		if (entity.get() instanceof EntityGadget entityGadget) {
			entityGadget.updateState(gadgetState);
			return 0;
78
		}
Akka's avatar
Akka committed
79
80

		return 1;
81
82
83
	}

	public int SetGroupGadgetStateByConfigId(int groupId, int configId, int gadgetState) {
84
85
		logger.debug("[LUA] Call SetGroupGadgetStateByConfigId with {},{},{}",
				groupId,configId,gadgetState);
Akka's avatar
Akka committed
86
87
88
89
90
91

		getSceneScriptManager().getScene().getEntities().values().stream()
				.filter(e -> e.getGroupId() == groupId)
				.filter(e -> e instanceof EntityGadget)
				.map(e -> (EntityGadget)e)
				.forEach(e -> e.updateState(gadgetState));
92
93
94
95
96
		
		return 0;
	}
	
	public int SetWorktopOptionsByGroupId(int groupId, int configId, int[] options) {
97
98
		logger.debug("[LUA] Call SetWorktopOptionsByGroupId with {},{},{}",
				groupId,configId,options);
Melledy's avatar
Melledy committed
99
		
100
101
102
		Optional<GameEntity> entity = getSceneScriptManager().getScene().getEntities().values().stream()
				.filter(e -> e.getConfigId() == configId && e.getGroupId() == groupId).findFirst();

Melledy's avatar
Melledy committed
103
104

		if (entity.isEmpty() || !(entity.get() instanceof EntityGadget gadget)) {
105
106
			return 1;
		}
Melledy's avatar
Melledy committed
107
108

		if (!(gadget.getContent() instanceof GadgetWorktop worktop)) {
109
110
111
			return 1;
		}
		
Melledy's avatar
Melledy committed
112
		worktop.addWorktopOptions(options);
113
		getSceneScriptManager().getScene().broadcastPacket(new PacketWorktopOptionNotify(gadget));
Melledy's avatar
Melledy committed
114
		
115
116
		return 0;
	}
Akka's avatar
Akka committed
117
118
119
120
121
122

	public int SetWorktopOptions(LuaTable table){
		logger.debug("[LUA] Call SetWorktopOptions with {}", printTable(table));
		// TODO
		return 0;
	}
123
	public int DelWorktopOptionByGroupId(int groupId, int configId, int option) {
124
125
		logger.debug("[LUA] Call DelWorktopOptionByGroupId with {},{},{}",groupId,configId,option);

126
127
128
		Optional<GameEntity> entity = getSceneScriptManager().getScene().getEntities().values().stream()
				.filter(e -> e.getConfigId() == configId && e.getGroupId() == groupId).findFirst();

Melledy's avatar
Melledy committed
129
		if (entity.isEmpty() || !(entity.get() instanceof EntityGadget gadget)) {
130
131
			return 1;
		}
Melledy's avatar
Melledy committed
132
133

		if (!(gadget.getContent() instanceof GadgetWorktop worktop)) {
134
135
136
			return 1;
		}
		
Melledy's avatar
Melledy committed
137
		worktop.removeWorktopOption(option);
138
		getSceneScriptManager().getScene().broadcastPacket(new PacketWorktopOptionNotify(gadget));
Melledy's avatar
Melledy committed
139
		
140
141
142
143
		return 0;
	}
	
	// Some fields are guessed
144
145
146
147
	public int AutoMonsterTide(int challengeIndex, int groupId, Integer[] ordersConfigId, int tideCount, int sceneLimit, int param6) {
		logger.debug("[LUA] Call AutoMonsterTide with {},{},{},{},{},{}",
				challengeIndex,groupId,ordersConfigId,tideCount,sceneLimit,param6);

148
		SceneGroup group = getSceneScriptManager().getGroupById(groupId);
149

150
151
152
		if (group == null || group.monsters == null) {
			return 1;
		}
153

154
		this.getSceneScriptManager().startMonsterTideInGroup(group, ordersConfigId, tideCount, sceneLimit);
155
156
157
158
		
		return 0;
	}
	
159
	public int AddExtraGroupSuite(int groupId, int suite) {
160
161
		logger.debug("[LUA] Call AddExtraGroupSuite with {},{}",
				groupId,suite);
Melledy's avatar
Melledy committed
162
163
164
165
166
		SceneGroup group = getSceneScriptManager().getGroupById(groupId);
		
		if (group == null || group.monsters == null) {
			return 1;
		}
Akka's avatar
Akka committed
167
168
169
170
		var suiteData = group.getSuiteByIndex(suite);
		if(suiteData == null){
			return 1;
		}
171
172
173
174
175
176
		// avoid spawn wrong monster
		if(getSceneScriptManager().getScene().getChallenge() != null)
			if(!getSceneScriptManager().getScene().getChallenge().inProgress() ||
					getSceneScriptManager().getScene().getChallenge().getGroup().id != groupId){
			return 0;
		}
Akka's avatar
Akka committed
177
178
		this.getSceneScriptManager().addGroupSuite(group, suiteData);

Melledy's avatar
Melledy committed
179
180
		return 0;
	}
Akka's avatar
Akka committed
181
182
183
	public int GoToGroupSuite(int groupId, int suite) {
		logger.debug("[LUA] Call GoToGroupSuite with {},{}",
				groupId,suite);
184
		SceneGroup group = getSceneScriptManager().getGroupById(groupId);
Akka's avatar
Akka committed
185
186
187
188
189
190
191
		if (group == null || group.monsters == null) {
			return 1;
		}
		var suiteData = group.getSuiteByIndex(suite);
		if(suiteData == null){
			return 1;
		}
192

Akka's avatar
Akka committed
193
194
195
196
197
		for(var suiteItem : group.suites){
			if(suiteData == suiteItem){
				continue;
			}
			this.getSceneScriptManager().removeGroupSuite(group, suiteItem);
198
		}
Akka's avatar
Akka committed
199
200
201
202
203
204
205
206
207
		this.getSceneScriptManager().addGroupSuite(group, suiteData);

		return 0;
	}
	public int RemoveExtraGroupSuite(int groupId, int suite) {
		logger.debug("[LUA] Call RemoveExtraGroupSuite with {},{}",
				groupId,suite);

		SceneGroup group = getSceneScriptManager().getGroupById(groupId);
208
209
210
		if (group == null || group.monsters == null) {
			return 1;
		}
Akka's avatar
Akka committed
211
212
213
214
		var suiteData = group.getSuiteByIndex(suite);
		if(suiteData == null){
			return 1;
		}
215

Akka's avatar
Akka committed
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
		this.getSceneScriptManager().removeGroupSuite(group, suiteData);

		return 0;
	}
	public int KillExtraGroupSuite(int groupId, int suite) {
		logger.debug("[LUA] Call KillExtraGroupSuite with {},{}",
				groupId,suite);

		SceneGroup group = getSceneScriptManager().getGroupById(groupId);
		if (group == null || group.monsters == null) {
			return 1;
		}
		var suiteData = group.getSuiteByIndex(suite);
		if(suiteData == null){
			return 1;
231
232
		}

Akka's avatar
Akka committed
233
		this.getSceneScriptManager().removeGroupSuite(group, suiteData);
234

Akka's avatar
Akka committed
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
		return 0;
	}
	// param3 (probably time limit for timed dungeons)
	public int ActiveChallenge(int challengeId, int challengeIndex, int timeLimitOrGroupId, int groupId, int objectiveKills, int param5) {
		logger.debug("[LUA] Call ActiveChallenge with {},{},{},{},{},{}",
				challengeId,challengeIndex,timeLimitOrGroupId,groupId,objectiveKills,param5);

		var challenge = ChallengeFactory.getChallenge(
				challengeId,
				challengeIndex,
				timeLimitOrGroupId,
				groupId,
				objectiveKills,
				param5,
				getSceneScriptManager().getScene(),
				getCurrentGroup().get()
				);

		if(challenge == null){
			return 1;
		}
256

Akka's avatar
Akka committed
257
258
259
260
261
262
		if(challenge instanceof DungeonChallenge dungeonChallenge){
			// set if tower first stage (6-1)
			dungeonChallenge.setStage(getSceneScriptManager().getVariables().getOrDefault("stage", -1) == 0);
		}

		getSceneScriptManager().getScene().setChallenge(challenge);
263
264
265
266
		challenge.start();
		return 0;
	}
	
267
	public int GetGroupMonsterCountByGroupId(int groupId) {
268
269
		logger.debug("[LUA] Call GetGroupMonsterCountByGroupId with {}",
				groupId);
270
271
272
273
274
		return (int) getSceneScriptManager().getScene().getEntities().values().stream()
								.filter(e -> e instanceof EntityMonster && e.getGroupId() == groupId)
								.count();
	}
	
Melledy's avatar
Melledy committed
275
	public int GetGroupVariableValue(String var) {
276
277
		logger.debug("[LUA] Call GetGroupVariableValue with {}",
				var);
Melledy's avatar
Melledy committed
278
		return getSceneScriptManager().getVariables().getOrDefault(var, 0);
279
280
	}
	
281
	public int SetGroupVariableValue(String var, int value) {
282
283
		logger.debug("[LUA] Call SetGroupVariableValue with {},{}",
				var, value);
284
		getSceneScriptManager().getVariables().put(var, value);
285
286
287
288
		return 0;
	}
	
	public LuaValue ChangeGroupVariableValue(String var, int value) {
289
290
291
		logger.debug("[LUA] Call ChangeGroupVariableValue with {},{}",
				var, value);

292
		getSceneScriptManager().getVariables().put(var, getSceneScriptManager().getVariables().get(var) + value);
293
294
		return LuaValue.ZERO;
	}
295
296
297
298

	/**
	 * Set the actions and triggers to designated group
	 */
299
	public int RefreshGroup(LuaTable table) {
300
		logger.debug("[LUA] Call RefreshGroup with {}",
301
				printTable(table));
302
303
304
305
306
307
308
309
310
311
		// Kill and Respawn?
		int groupId = table.get("group_id").toint();
		int suite = table.get("suite").toint();
		
		SceneGroup group = getSceneScriptManager().getGroupById(groupId);
		
		if (group == null || group.monsters == null) {
			return 1;
		}
		
312
		getSceneScriptManager().refreshGroup(group, suite);
313
		
314
315
		return 0;
	}
Akka's avatar
Akka committed
316

Melledy's avatar
Melledy committed
317
	public int GetRegionEntityCount(LuaTable table) {
318
		logger.debug("[LUA] Call GetRegionEntityCount with {}",
Akka's avatar
Akka committed
319
				printTable(table));
Melledy's avatar
Melledy committed
320
321
322
		int regionId = table.get("region_eid").toint();
		int entityType = table.get("entity_type").toint();

Akka's avatar
Akka committed
323
324
		var region = this.getSceneScriptManager().getRegionById(regionId);

Melledy's avatar
Melledy committed
325
326
327
328
		if (region == null) {
			return 0;
		}

Akka's avatar
Akka committed
329
		return (int) region.getEntities().stream().filter(e -> e >> 24 == entityType).count();
Melledy's avatar
Melledy committed
330
	}
Akka's avatar
Akka committed
331

332
	public void PrintContextLog(String msg) {
333
		logger.info("[LUA] " + msg);
334
	}
Akka's avatar
Akka committed
335

336
337
338
339
	public int TowerCountTimeStatus(int isDone, int var2){
		logger.debug("[LUA] Call TowerCountTimeStatus with {},{}",
				isDone,var2);
		// TODO record time
Akka's avatar
Akka committed
340
341
		return 0;
	}
Akka's avatar
Akka committed
342
343
	public int GetGroupMonsterCount(){
		logger.debug("[LUA] Call GetGroupMonsterCount ");
344
345

		return (int) getSceneScriptManager().getScene().getEntities().values().stream()
Akka's avatar
Akka committed
346
347
				.filter(e -> e instanceof EntityMonster &&
						e.getGroupId() == getCurrentGroup().map(sceneGroup -> sceneGroup.id).orElse(-1))
348
				.count();
Akka's avatar
Akka committed
349
350
	}
	public int SetMonsterBattleByGroup(int var1, int var2, int var3){
351
352
		logger.debug("[LUA] Call SetMonsterBattleByGroup with {},{},{}",
				var1,var2,var3);
353
		// TODO
Akka's avatar
Akka committed
354
355
356
357
		return 0;
	}

	public int CauseDungeonFail(int var1){
358
359
360
361
362
		logger.debug("[LUA] Call CauseDungeonFail with {}",
				var1);

		return 0;
	}
363

364
365
366
	public int GetGroupVariableValueByGroup(String name, int groupId){
		logger.debug("[LUA] Call GetGroupVariableValueByGroup with {},{}",
				name,groupId);
367

368
		return getSceneScriptManager().getVariables().getOrDefault(name, 0);
369
370
371
372
373
374
375
376
377
378
379
380
	}

	public int SetIsAllowUseSkill(int canUse, int var2){
		logger.debug("[LUA] Call SetIsAllowUseSkill with {},{}",
				canUse,var2);

		getSceneScriptManager().getScene().broadcastPacket(new PacketCanUseSkillNotify(canUse == 1));
		return 0;
	}

	public int KillEntityByConfigId(LuaTable table){
		logger.debug("[LUA] Call KillEntityByConfigId with {}",
381
				printTable(table));
382
383
384
385
386
387
388
		var configId = table.get("config_id");
		if(configId == LuaValue.NIL){
			return 1;
		}

		var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId.toint());
		if(entity == null){
Akka's avatar
Akka committed
389
			return 0;
390
391
		}
		getSceneScriptManager().getScene().killEntity(entity, 0);
Akka's avatar
Akka committed
392
393
		return 0;
	}
394

395
396
397
398
	public int SetGroupVariableValueByGroup(String key, int value, int groupId){
		logger.debug("[LUA] Call SetGroupVariableValueByGroup with {},{},{}",
				key,value,groupId);

399
400
401
402
403
404
405
406
407
408
		getSceneScriptManager().getVariables().put(key, value);
		return 0;
	}

	public int CreateMonster(LuaTable table){
		logger.debug("[LUA] Call CreateMonster with {}",
				printTable(table));
		var configId = table.get("config_id").toint();
		var delayTime = table.get("delay_time").toint();

Akka's avatar
Akka committed
409
410
411
412
413
		if(getCurrentGroup().isEmpty()){
			return 1;
		}

		getSceneScriptManager().spawnMonstersByConfigId(getCurrentGroup().get(), configId, delayTime);
414
415
416
417
418
419
420
		return 0;
	}

	public int TowerMirrorTeamSetUp(int team, int var1) {
		logger.debug("[LUA] Call TowerMirrorTeamSetUp with {},{}",
				team,var1);

421
		getSceneScriptManager().unloadCurrentMonsterTide();
422
423
		getSceneScriptManager().getScene().getPlayers().get(0).getTowerManager().mirrorTeamSetUp(team-1);

424
425
426
		return 0;
	}

427
428
429
430
431
	public int CreateGadget(LuaTable table){
		logger.debug("[LUA] Call CreateGadget with {}",
				printTable(table));
		var configId = table.get("config_id").toint();

Akka's avatar
Akka committed
432
		var group = getCurrentGroup();
433
434
		
		if (group.isEmpty()) {
Akka's avatar
Akka committed
435
436
			return 1;
		}
437
		
Akka's avatar
Akka committed
438
439
		var gadget = group.get().gadgets.get(configId);
		var entity = getSceneScriptManager().createGadget(group.get().id, group.get().block_id, gadget);
440
		
Akka's avatar
Akka committed
441
		getSceneScriptManager().addEntity(entity);
442

Akka's avatar
Akka committed
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
		return 0;
	}
	public int CheckRemainGadgetCountByGroupId(LuaTable table){
		logger.debug("[LUA] Call CheckRemainGadgetCountByGroupId with {}",
				printTable(table));
		var groupId = table.get("group_id").toint();

		var count = getSceneScriptManager().getScene().getEntities().values().stream()
				.filter(g -> g instanceof EntityGadget entityGadget && entityGadget.getGroupId() == groupId)
				.count();
		return (int)count;
	}

	public int GetGadgetStateByConfigId(int groupId, int configId){
		logger.debug("[LUA] Call GetGadgetStateByConfigId with {},{}",
				groupId, configId);
Akka's avatar
Akka committed
459
460
461
462
463

		if(groupId == 0){
			groupId = getCurrentGroup().get().id;
		}
		final int realGroupId = groupId;
Akka's avatar
Akka committed
464
		var gadget = getSceneScriptManager().getScene().getEntities().values().stream()
Akka's avatar
Akka committed
465
				.filter(g -> g instanceof EntityGadget entityGadget && entityGadget.getGroupId() == realGroupId)
Akka's avatar
Akka committed
466
467
468
				.filter(g -> g.getConfigId() == configId)
				.findFirst();
		if(gadget.isEmpty()){
Akka's avatar
Akka committed
469
			return 1;
Akka's avatar
Akka committed
470
		}
Akka's avatar
Akka committed
471
		return ((EntityGadget)gadget.get()).getState();
Akka's avatar
Akka committed
472
	}
Akka's avatar
Akka committed
473
474

	public int MarkPlayerAction(int var1, int var2, int var3, int var4){
Akka's avatar
Akka committed
475
476
		logger.debug("[LUA] Call MarkPlayerAction with {},{},{},{}",
				var1, var2,var3,var4);
Akka's avatar
Akka committed
477
478
479
480
481
482
483
484

		return 0;
	}

	public int AddQuestProgress(String var1){
		logger.debug("[LUA] Call AddQuestProgress with {}",
				var1);

Akka's avatar
Akka committed
485
486
487
488
489
        for(var player : getSceneScriptManager().getScene().getPlayers()){
            player.getQuestManager().triggerEvent(QuestTrigger.QUEST_COND_LUA_NOTIFY, var1);
            player.getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_LUA_NOTIFY, var1);
        }

Akka's avatar
Akka committed
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
		return 0;
	}

	/**
	 * change the state of gadget
	 */
	public int ChangeGroupGadget(LuaTable table){
		logger.debug("[LUA] Call ChangeGroupGadget with {}",
				printTable(table));
		var configId = table.get("config_id").toint();
		var state = table.get("state").toint();

		var entity = getSceneScriptManager().getScene().getEntityByConfigId(configId);
		if(entity == null){
			return 1;
		}

507
508
		if (entity instanceof EntityGadget entityGadget) {
			entityGadget.updateState(state);
Akka's avatar
Akka committed
509
			return 0;
Akka's avatar
Akka committed
510
		}
Akka's avatar
Akka committed
511

Akka's avatar
Akka committed
512
		return 1;
513
	}
Akka's avatar
Akka committed
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556

    public int GetEntityType(int entityId){
        var entity = getSceneScriptManager().getScene().getEntityById(entityId);
        if(entity == null){
            return EntityType.None.getValue();
        }

        return entity.getEntityType();
    }

    public int GetQuestState(int entityId, int questId){
        var player = getSceneScriptManager().getScene().getWorld().getHost();

        var quest = player.getQuestManager().getQuestById(questId);
        if(quest == null){
            return QuestState.QUEST_STATE_NONE.getValue();
        }

        return quest.getState().getValue();
    }

    public int ShowReminder(int reminderId){
        getSceneScriptManager().getScene().broadcastPacket(new PacketDungeonShowReminderNotify(reminderId));
        return 0;
    }

    public int RemoveEntityByConfigId(int groupId, int entityType, int configId){
        logger.debug("[LUA] Call RemoveEntityByConfigId");

        var entity = getSceneScriptManager().getScene().getEntities().values().stream()
            .filter(e -> e.getGroupId() == groupId)
            .filter(e -> e.getEntityType() == entityType)
            .filter(e -> e.getConfigId() == configId)
            .findFirst();

        if(entity.isEmpty()){
            return 1;
        }

        getSceneScriptManager().getScene().removeEntity(entity.get());

        return 0;
    }
557
}