-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmainProt.ttslua
More file actions
139 lines (124 loc) · 6.71 KB
/
mainProt.ttslua
File metadata and controls
139 lines (124 loc) · 6.71 KB
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
local objectprot = { -- the controller prototype that will hold the ancestral functions
protName = "objectprot"
}
objectprot.__index = objectprot -- if you're a kid and can't find something ask your parents
objectprot.__call = function(sourceTable) -- attempting to call an instance as a function will return a reference to its attached object.
local guid = sourceTable.guid
if not guid then
log("tried to dereference an instance, but it had no guid attached!")
return
end
local obj = getObjectFromGUID(guid) -- followup: once we get binser, we can cache the direct object ref in the instance rather than using getObjectGUID each time
if obj == nil then
log("self() object with guid " .. guid .. " does not exist!")
-- followup: do we want an option to return a fake object? one that will just eat api function calls without complaining in loud red text
end
return obj
end
function objectprot:new(baseTable, ...) -- initializes a new instance of a class based on target obj and any other arguments. do not call from instance, only from prototype. for reference a prototype must have prot.__index == prot
local out = setmetatable(baseTable or {}, self)
out.__index = out --unfortunately __index needs to be set manually for each new prototype, it's called with rawget() and thus not heritable.
out.__call = objectprot.__call -- __call() should always be the same so we set it directly to objectprot's to avoid an extra metatable lookup.
return setmetatable(out, self) -- makes an empty table and sets its metatable to self. the setmetatable function returns its first arg
local guid = type(initarg) == "userdata" and initarg.guid or initarg -- initarg is either userdata or a guid string. if it's userdata, get guid, else it should be a string and we can assign directly
assert(type(guid) == "string", "init argument is not a not valid (userdata or guid), it's a " .. type(initarg))
out.guid = guid -- every instance needs a guid
return out:init(...) -- any additional args are passed on to init
end
function objectprot:init() -- initializes all internal, instance-specific variables. this is run during self:newInstance(). should be overriden/extended in children, but always return self.
return self
end
function objectprot:cleanupInstance() -- deletes the instance. override/extend this to clean up any other stuff you need
-- self:resetUI() -- for example you might want to delete ui if it's not pointing to anything anymore
instanceList[self.protName][self.guid] = nil
end
-- functions to read and write script_state. can be overriden/extended ofc
-- followup: use binser or some other format (maybe a FlatBuffer/FlexBuffer?) instead of JSON if this turns out to be too slow
-- i also considered using getTable instead of decoding script_state but was told they're about equally slow since getTable does a deepcopy.
function objectprot:readSave()
local raw = JSON.decode(self().script_state)
return type(raw) == "table" and raw or {} -- falls back to returning an empty table if script_state is not a table (e.g a nil or an empty string) followup: maybe handle non-table retuns in children instead
end
function objectprot:writeSave(arg)
self().script_state = JSON.encode(arg)
end
-- a couple misecllaneous ui functions for convenience. followup: should i move these into a separate require()?
-- also followup: 2 optional arguments in the middle of this definition is kind of pushing it. should the arguments be packed into a table instead?
function objectprot:makeContextMenu(methodName, closure, keep_open, ...) -- this lets us easily put table:func() type functions into context menus and pass arguments to them.
if methodName == "" then
self().addContextMenuItem("-------", function() return end, true)
return
end
local wrappedClosure
local vargs = ...
if closure then
wrappedClosure = function(player, obj)
return closure(self, player, obj, vargs) -- if the closure only needs vargs, it has to be called as closure(_,_,_, vargs) which is kinda ugly. but maybe those can just be passed in as upvalues?
end
else
wrappedClosure = function(player, obj)
return self[methodName](self, player, obj, vargs)
end
end
self().addContextMenuItem(methodName, wrappedClosure, keep_open or false)
end
-- folowup: add auto bbcode maybe?
function objectprot:playerPrint(str, player, color) -- to print to all with color, should be called as self:playerPrint(str, nil, color)
if player then
printToColor(str, player, color)
else
printToAll(str, color)
end
end
function objectprot:resetUI()
local realObj = self()
realObj.clearInputs()
realObj.clearButtons()
realObj.clearContextMenu()
realObj.highlightOff()
end
-- followup: use this automate createButton() generation
-- ripped from https://github.com/tjakubo2/TTS_xwing/blob/2db37acb2960474f095fb8d47fa8654044af972e/Global.-1.ttslua#L3398
local charWidthTable = {
['`'] = 2381, ['~'] = 2381, ['1'] = 1724, ['!'] = 1493, ['2'] = 2381,
['@'] = 4348, ['3'] = 2381, ['#'] = 3030, ['4'] = 2564, ['$'] = 2381,
['5'] = 2381, ['%'] = 3846, ['6'] = 2564, ['^'] = 2564, ['7'] = 2174,
['&'] = 2777, ['8'] = 2564, ['*'] = 2174, ['9'] = 2564, ['('] = 1724,
['0'] = 2564, [')'] = 1724, ['-'] = 1724, ['_'] = 2381, ['='] = 2381,
['+'] = 2381, ['q'] = 2564, ['Q'] = 3226, ['w'] = 3704, ['W'] = 4167,
['e'] = 2174, ['E'] = 2381, ['r'] = 1724, ['R'] = 2777, ['t'] = 1724,
['T'] = 2381, ['y'] = 2564, ['Y'] = 2564, ['u'] = 2564, ['U'] = 3030,
['i'] = 1282, ['I'] = 1282, ['o'] = 2381, ['O'] = 3226, ['p'] = 2564,
['P'] = 2564, ['['] = 1724, ['{'] = 1724, [']'] = 1724, ['}'] = 1724,
['|'] = 1493, ['\\'] = 1923, ['a'] = 2564, ['A'] = 2777, ['s'] = 1923,
['S'] = 2381, ['d'] = 2564, ['D'] = 3030, ['f'] = 1724, ['F'] = 2381,
['g'] = 2564, ['G'] = 2777, ['h'] = 2564, ['H'] = 3030, ['j'] = 1075,
['J'] = 1282, ['k'] = 2381, ['K'] = 2777, ['l'] = 1282, ['L'] = 2174,
[';'] = 1282, [':'] = 1282, ['\''] = 855, ['"'] = 1724, ['z'] = 1923,
['Z'] = 2564, ['x'] = 2381, ['X'] = 2777, ['c'] = 1923, ['C'] = 2564,
['v'] = 2564, ['V'] = 2777, ['b'] = 2564, ['B'] = 2564, ['n'] = 2564,
['N'] = 3226, ['m'] = 3846, ['M'] = 3846, [','] = 1282, ['<'] = 2174,
['.'] = 1282, ['>'] = 2174, ['/'] = 1923, ['?'] = 2174, [' '] = 1282,
['avg'] = 2500
}
local function calcButtonWidth(str) -- Get real string length per char table.
local len = 0
for i = 1, #str do
local c = str:sub(i,i)
if StringLen.charWidthTable[c] ~= nil then
len = len + StringLen.charWidthTable[c]
else
len = len + StringLen.charWidthTable.avg
end
end
return len
end
return {
mainProt = objectprot,
protlist = protList,
instanceList = instanceList,
functions = {
getObjectProt = getObjectProt,
initObject = initObject
}
}