-
Notifications
You must be signed in to change notification settings - Fork 12
/
Insane Anti Lag.rb
686 lines (640 loc) · 28.5 KB
/
Insane Anti Lag.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
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
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
#===============================================================================
# TheoAllen - Insane Anti Lag
# Version : 1.1b
# Language : English
#-------------------------------------------------------------------------------
# With help from following people :
# - Tsukihime
# - KilloZapit
# - Galv
#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Contact :
#-------------------------------------------------------------------------------
# Discord @ Theo#3034
# Twiiter @ theolized
#===============================================================================
($imported ||= {})[:Theo_AntiLag] = true
#===============================================================================
# Change Logs:
# ------------------------------------------------------------------------------
# 2018.12.11 - Added extra rescue to prevent crash with Shaz's mouse script
# 2015.02.20 - Added page check enhancer to work with parallel process
# 2015.01.25 - Compatibility with Shaz's Mouse Script. def events_xy now should
# always return array,
# - Avoid error 'undefined method delete_sprite for nilClass'
# 2015.01.01 - Avoid unexpected error 'undefined method spriteset for scene'
# 2014.12.05 - Finished
#===============================================================================
=begin
------------------------------------------
*) Introduction :
------------------------------------------
As most of you already know, lag is common problem in RPG Maker games. You may
started to think it was because you have many events on map. And so, to avoid
lag, you split your map into part and limiting the event as well.
It's not entirely wrong because when you have a lot of events, program need
to checks all events. However, it wasn't done efficienly. This script
increase the efficiency on how default script works and prevent unecessary
update when it's not needed to gain speed.
However, I can not guarantee that it will have high compatibility since I
overwrite most of stuff. I will likely to make compatibility with my own
scripts. But I'm not sure about someone's script.
------------------------------------------
*) How to use :
------------------------------------------
Put this script below material but above main. And it's recommended to put
this above most of custom script.
Set the type of optimization that you like in config
You may disable some kind of optimization if you have compatibility issues
------------------------------------------
*) Terms of use :
------------------------------------------
Credit me, TheoAllen. You are free to edit this script by your own. As long
as you don't claim it's yours. For commercial purpose, don't forget to give me
a free copy of the game.
Additional people to put in credit credit list are listed in header above.
You should give them a free copy of your game as well if it's commercial ;)
=end
#==============================================================================
# Configurations :
#==============================================================================
module Theo
module AntiLag
#=============================================================================
# *) Normal optimization
#-----------------------------------------------------------------------------
# This kind of optimization is for normal usage. These optimization may works
# only if the total events on map is around 200 - 300.
#=============================================================================
#-----------------------------------------------------------------------------
Optimize_XY = true
#-----------------------------------------------------------------------------
# By default, event position checking is to check ALL the events on the map.
# If you want to check an event is in x,y position, it ask EVERY event if
# their position is match. By using this optimization, all events registered
# to the map table so that the engine won't check all events on map. Instead,
# it checks if there's event on a certain table.
#
# This kind of optimization is recommended to set it to true. However, it may
# not compatible with any pixel movement since they using box collider instead
# of using grid.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
Optimize_Event = true
#-----------------------------------------------------------------------------
# By default, if the engine want to check if there's event starting, they
# checked ALL the events on map. They did it in every frame. If you have 200
# events in map, they checked 60 x 200 events per second.
#
# By using this optimization, if event is triggered, it will be registered
# into a record. And then engine checked if there is event on the record
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
Optimize_Sprite = true
#-----------------------------------------------------------------------------
# By default, the engine still update every sprites which located off screen.
# This might waste the time since updating it is not necessary sometimes. By
# using this optimization, it ignores character sprite that already off screen
#-----------------------------------------------------------------------------
#=============================================================================
# *) Insane optimization
#-----------------------------------------------------------------------------
# This kind of optimization is to overcome the problem of using event beyond
# 230 on the map which normal optimization is failed to do. This optimization
# uses insane algorithm like table search and dispose any unecessary sprite on
# the fly.
#=============================================================================
#-----------------------------------------------------------------------------
Table_Limit_Search = 230
#-----------------------------------------------------------------------------
# Table search is a custom algorithm to grab events based on the map table.
# Instead of iterating all events and checked them if they're on the screen,
# it checked the visible map table instead. So, event that located far away
# from the player won't be updated. But any parallel process or autorun events
# or move route for an event will still updated.
#
# Table limit search means that if the total of events on map is above the
# limit, this script will switch event update algorithm to table search. So
# you will not worrying about having 999 or even 10.000 events on map.
#
# Table search required Optimize_XY to set to true.
#
# If you don't want to use table search algorithm, just put the parameter
# to nil.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
Table_Range_Search = 2
#-----------------------------------------------------------------------------
# This determine how far table search will perform check. Putting 3 means that
# it will update the event that located 3 tiles away from the screen.
#
# Keep in mind that the longer range search will affect the performance as
# well. It's recommended to put it between 2 - 4
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
Dispose_Sprite = true
#-----------------------------------------------------------------------------
# Sometimes, limiting the events which is being updated is not enough. Sprite
# objects is still being performace killer. Disposing sprite which is already
# off screen will greatly affect the performance. This kind of optimization
# is enabled only if the table search is used.
#
# Disposing sprite on the fly might be problematic sometimes. When something
# wrong happened, you can disable dispose sprite be setting this to false.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
PageCheck_Enchancer = true
#-----------------------------------------------------------------------------
# When a lot of events put together in one map, and each has 20 pages, and
# you have parallel process to change the variable or switches, you will see
# noticable lag.
#
# This kind of enhancer only refresh the visible events on the screen or when
# the event is on the visible range. So that it prevents to refresh all events
# This concept is a fool proof to the player since they will never know what
# is in their visible range
#
# However, this may ruin some system since this concept is still experimental.
#-----------------------------------------------------------------------------
end
end
#===============================================================================
# *) Final note :
#-------------------------------------------------------------------------------
# After all, these are just my attempt to speed up the game. Performance are
# still under influence by many factors. These include but may not limited to
#
# - Your CPU speed
# - Your laptop / PC temperature
# - How much power do you give for your CPU
# - Multi tasking
# - Someone's script
#
# I once used RM in old computer. When I switched to more advanced laptop, I
# saw that 60 FPS is really smooth.
#
# If your CPU seems overheat, turn off your laptop / PC for a while for cooling.
# My laptop was once overheat due to broken fan. When I played my own game I
# got 10 FPS. I made my own antilag and no one of them worked until I realized
# my laptop was overheat.
#
# Power saver mode in laptop may affect performance. Try to go high performance
# instead and let see if the lag gone. Once my friend played my game using power
# saver mode, and he got 15 FPS.
#
# If you have many programs running at same time, it may cause a little lag in
# RPG Maker games. Something like the screen won't be updated for a while.
#
# Some scripts can affect performance if it's not done right. This antilag
# script is tested using default script without additional scripts which
# directly affect something on map.
#
#-------------------------------------------------------------------------------
# *) Below this line is sacred place to visit. Unless you have enough skill,
# do not try to enter or any risk is yours.
#===============================================================================
#===============================================================================
# ** MapTable
#-------------------------------------------------------------------------------
# This class used to register the event into 2D table to increase performance
#===============================================================================
class MapTable
#-----------------------------------------------------------------------------
# * Initialize
#-----------------------------------------------------------------------------
def initialize
@table = []
($game_map.width + 1).times do |x|
@table[x] = []
($game_map.height + 1).times do |y|
@table[x][y] = []
end
end
end
#-----------------------------------------------------------------------------
# * Set value
#-----------------------------------------------------------------------------
def set(x,y,val)
@table[x][y] << val
end
#-----------------------------------------------------------------------------
# * Get array
#-----------------------------------------------------------------------------
def get(x,y)
@table[x][y] rescue []
end
end
#===============================================================================
# ** Array
#===============================================================================
class Array
# Just a fool proof
def values
return self
end
end
#===============================================================================
# ** Game_Map
#===============================================================================
class Game_Map
#-----------------------------------------------------------------------------
# * Public attributes
#-----------------------------------------------------------------------------
attr_accessor :event_redirect # Redirect events
attr_reader :forced_update_events # To keep force move route updated
attr_reader :keep_update_events # To keep parallel process updated
attr_reader :cached_events # To store event that need to be updated
attr_reader :starting_events # To store activated event
attr_reader :table # 2D Map table
#-----------------------------------------------------------------------------
# * Constant
#-----------------------------------------------------------------------------
EVENT_LIMIT = Theo::AntiLag::Table_Limit_Search
RANGE = Theo::AntiLag::Table_Range_Search
#-----------------------------------------------------------------------------
# * Alias method : Setup Events
#-----------------------------------------------------------------------------
alias theo_antilag_setup_events setup_events
def setup_events
@table = MapTable.new
@forced_update_events = []
@keep_update_events = []
@starting_events = []
@refreshed_events = []
theo_antilag_setup_events
select_on_screen_events
end
#-----------------------------------------------------------------------------
# * Overwrite method : Events
#-----------------------------------------------------------------------------
def events
@event_redirect ? @cached_events : @events
end
#///////////////////////////////////////////////////////////////////////////////
if Theo::AntiLag::Optimize_XY
#///////////////////////////////////////////////////////////////////////////////
#-----------------------------------------------------------------------------
# * Overwrite method : Event XY
#-----------------------------------------------------------------------------
def events_xy(x, y)
@table.get(x,y) || []
end
#-----------------------------------------------------------------------------
# * Overwrite method : Event XY nt
#-----------------------------------------------------------------------------
def events_xy_nt(x, y)
@table.get(x,y).select do |event|
event.pos_nt?(x, y)
end
end
#///////////////////////////////////////////////////////////////////////////////
end
#///////////////////////////////////////////////////////////////////////////////
if Theo::AntiLag::Optimize_Event
#///////////////////////////////////////////////////////////////////////////////
#-----------------------------------------------------------------------------
# * Overwrite method : Setup starting event
#-----------------------------------------------------------------------------
def setup_starting_map_event
event = @starting_events[0]
event.clear_starting_flag if event
@interpreter.setup(event.list, event.id) if event
event
end
#-----------------------------------------------------------------------------
# * Overwrite method : Any event starting?
#-----------------------------------------------------------------------------
def any_event_starting?
!@starting_events.empty?
end
#///////////////////////////////////////////////////////////////////////////////
end
#///////////////////////////////////////////////////////////////////////////////
#-----------------------------------------------------------------------------
# * Overwrite method : Refresh
#-----------------------------------------------------------------------------
def refresh
return table_refresh if table_update? && Theo::AntiLag::PageCheck_Enchancer
@events.each_value {|event| next if event.never_refresh; event.refresh }
@common_events.each {|event| event.refresh }
refresh_tile_events
@need_refresh = false
end
#-----------------------------------------------------------------------------
# * New method : Refresh event by table search
#-----------------------------------------------------------------------------
def table_refresh
@refreshed_events = []
@tile_events = []
@common_events.each {|event| event.refresh }
@need_refresh = false
end
#-----------------------------------------------------------------------------
# * Overwrite method : Update events
#-----------------------------------------------------------------------------
def update_events
last_events = (@cached_events.dup rescue @events.values)
select_on_screen_events
events = @cached_events | @keep_update_events | @forced_update_events
if Theo::AntiLag::Dispose_Sprite
offscreen_events = last_events - events
offscreen_events.each {|event| event.delete_sprite}
end
events.each {|event| event.update}
@common_events.each {|event| event.update}
end
#-----------------------------------------------------------------------------
# * New method : Select on screen events
#-----------------------------------------------------------------------------
def select_on_screen_events
unless table_update?
@cached_events = @events.values
return
end
#---------------------------------------------------------------------------
# * Table search algorithm
#---------------------------------------------------------------------------
new_dpx = display_x.to_i
new_dpy = display_y.to_i
dpx = loop_horizontal? ? new_dpx - RANGE : [new_dpx - RANGE, 0].max
dpy = loop_vertical? ? new_dpy - RANGE : [new_dpy - RANGE, 0].max
sw = (Graphics.width >> 5) + RANGE * 2
sh = (Graphics.height >> 5) + RANGE * 2
@cached_events = []
sw.times do |x|
sh.times do |y|
xpos = loop_horizontal? ? (x + dpx) % width : x + dpx
ypos = loop_vertical? ? (y + dpy) % height : y + dpy
next if xpos >= width || ypos >= height
ary = @table.get(xpos, ypos)
ary.each do |ev|
unless @refreshed_events.include?(ev.id)
ev.refresh
@tile_events << ev if ev.tile?
@refreshed_events << ev.id
end
end if Theo::AntiLag::PageCheck_Enchancer
@cached_events += ary
end
end
@cached_events.uniq!
end
#-----------------------------------------------------------------------------
# * Check if table search need to be performed or not
#-----------------------------------------------------------------------------
def table_update?
EVENT_LIMIT && @events.size > EVENT_LIMIT && Theo::AntiLag::Optimize_XY
end
end
#===============================================================================
# ** Game_Temp
#===============================================================================
class Game_Temp
attr_reader :event_sprites
#-----------------------------------------------------------------------------
# * Alias method : Initialize
#-----------------------------------------------------------------------------
alias theo_antilag_init initialize
def initialize
theo_antilag_init
@event_sprites = {}
end
end
#===============================================================================
# ** Game_CharacterBase
#===============================================================================
class Game_CharacterBase
#-----------------------------------------------------------------------------
# * Empty method : Sprite
#-----------------------------------------------------------------------------
def sprite
return nil
end
#-----------------------------------------------------------------------------
# * Empty method : Sprite =
#-----------------------------------------------------------------------------
def sprite=(spr)
end
end
#===============================================================================
# ** Game_Event
#===============================================================================
class Game_Event
#-----------------------------------------------------------------------------
# * Never refesh flag
#-----------------------------------------------------------------------------
attr_reader :never_refresh
#-----------------------------------------------------------------------------
# * Alias method : Initialize
#-----------------------------------------------------------------------------
alias theo_antilag_init initialize
def initialize(map_id, event)
theo_antilag_init(map_id, event)
$game_map.table.set(x,y,self)
@last_x = @x
@last_y = @y
end
#-----------------------------------------------------------------------------
# * Alias method : Update
#-----------------------------------------------------------------------------
alias theo_antilag_update update
def update
if (sprite && sprite.disposed?) || sprite.nil?
spriteset = SceneManager.scene.spriteset
return unless spriteset
spriteset.add_sprite(self)
end
theo_antilag_update
if Theo::AntiLag::Optimize_XY && (@last_x != @x || @last_y != @y)
$game_map.table.get(@last_x, @last_y).delete(self)
$game_map.table.set(@x,@y,self)
@last_x = @x
@last_y = @y
end
end
#-----------------------------------------------------------------------------
# * Alias method : Start
#-----------------------------------------------------------------------------
alias theo_antilag_start start
def start
theo_antilag_start
return unless Theo::AntiLag::Optimize_Event
$game_map.starting_events << self if @starting
end
#-----------------------------------------------------------------------------
# * Alias method : Clear starting flag
#-----------------------------------------------------------------------------
alias theo_antilag_clear_start clear_starting_flag
def clear_starting_flag
theo_antilag_clear_start
return unless Theo::AntiLag::Optimize_Event
$game_map.starting_events.delete(self)
end
#-----------------------------------------------------------------------------
# * Alias method : Setup page setting
#-----------------------------------------------------------------------------
alias theo_antilag_setup_page_settings setup_page_settings
def setup_page_settings
theo_antilag_setup_page_settings
if @event.pages.size == 1 && no_condition?(@event.pages[0].condition)
@never_refresh = true
end
if @trigger == 3 || @interpreter
$game_map.keep_update_events << self
$game_map.keep_update_events.uniq!
else
$game_map.keep_update_events.delete(self)
end
end
#-----------------------------------------------------------------------------
# * Check if the events has no page condition
#-----------------------------------------------------------------------------
def no_condition?(page)
!page.switch1_valid && !page.switch2_valid && !page.variable_valid &&
!page.self_switch_valid && !page.item_valid && !page.actor_valid
end
#-----------------------------------------------------------------------------
# * Delete sprite
#-----------------------------------------------------------------------------
def delete_sprite
sprset = SceneManager.scene.spriteset
return unless sprset
SceneManager.scene.spriteset.delete_sprite(sprite)
end
#-----------------------------------------------------------------------------
# * Overwrite method : Force move route
#-----------------------------------------------------------------------------
def force_move_route(move_route)
super
$game_map.forced_update_events << self
$game_map.forced_update_events.uniq!
end
#-----------------------------------------------------------------------------
# * Overwrite method : Restore move route
#-----------------------------------------------------------------------------
def restore_move_route
super
$game_map.forced_update_events.delete(self)
end
#-----------------------------------------------------------------------------
# * Overwrite method : Sprite
#-----------------------------------------------------------------------------
def sprite
$game_temp.event_sprites[@id]
end
#-----------------------------------------------------------------------------
# * Overwrite method : Sprite =
#-----------------------------------------------------------------------------
def sprite=(spr)
$game_temp.event_sprites[@id] = spr
end
end
#===============================================================================
# ** Sprite Character
#===============================================================================
class Sprite_Character
#-----------------------------------------------------------------------------
# * Alias method : Initialize
#-----------------------------------------------------------------------------
alias theo_antilag_init initialize
def initialize(viewport, character = nil)
character.sprite = self if character
theo_antilag_init(viewport, character)
end
#-----------------------------------------------------------------------------
# * Alias method : Update
#-----------------------------------------------------------------------------
alias theo_antilag_update update
def update
@sx = @character.screen_x
@sy = @character.screen_y
if Theo::AntiLag::Optimize_Sprite && !need_update?
self.visible = false
return
end
theo_antilag_update
end
#-----------------------------------------------------------------------------
# * New method : Determine if on screen
#-----------------------------------------------------------------------------
def need_update?
return true if graphic_changed?
return true if @character.animation_id > 0
return true if @balloon_sprite
return true if @character.balloon_id != 0
w = Graphics.width
h = Graphics.height
cw = @cw || 32
ch = @ch || 32
@sx.between?(-cw,w+cw) && @sy.between?(0,h+ch)
end
#-----------------------------------------------------------------------------
# * Overwrite update position.
# To limit screen_x and screen_y to be called many times
#-----------------------------------------------------------------------------
def update_position
move_animation(@sx - x, @sy - y)
self.x = @sx
self.y = @sy
self.z = @character.screen_z
end
#-----------------------------------------------------------------------------
# * Overwrite animation origin
# Since X and Y axis of sprite is not updated when off screen
#-----------------------------------------------------------------------------
def set_animation_origin
if @animation.position == 3
if viewport == nil
@ani_ox = Graphics.width / 2
@ani_oy = Graphics.height / 2
else
@ani_ox = viewport.rect.width / 2
@ani_oy = viewport.rect.height / 2
end
else
@ani_ox = @sx - ox + width / 2
@ani_oy = @sy - oy + height / 2
if @animation.position == 0
@ani_oy -= height / 2
elsif @animation.position == 2
@ani_oy += height / 2
end
end
end
end
#===============================================================================
# ** Spriteset_Map
#===============================================================================
class Spriteset_Map
#-----------------------------------------------------------------------------
# * Alias method : create character
#-----------------------------------------------------------------------------
alias theo_antilag_create_characters create_characters
def create_characters
$game_map.event_redirect = Theo::AntiLag::Dispose_Sprite
theo_antilag_create_characters
$game_map.event_redirect = false
end
#-----------------------------------------------------------------------------
# * New method : delete sprite
#-----------------------------------------------------------------------------
def delete_sprite(spr)
return unless spr
return if spr.disposed?
@character_sprites.delete(spr)
spr.dispose
end
#-----------------------------------------------------------------------------
# * New method : add sprite
#-----------------------------------------------------------------------------
def add_sprite(char)
spr = Sprite_Character.new(@viewport1, char)
@character_sprites.push(spr)
end
end
#===============================================================================
# ** Scene_Base
#===============================================================================
class Scene_Base
attr_reader :spriteset
end