-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAUID_gmnotes.ttslua
152 lines (136 loc) · 5.63 KB
/
AUID_gmnotes.ttslua
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
-- an AUID (Actually Unique ID) is a dumb integer that is always unique for each object
-- AUID is set and incremented every time we see an object without one, or each time a new object spawns from scratch.
-- AUIDs are unique keys that are stored in a table. AUIDs are keys that can point at 1 of 3 types of values-
-- (userdata) associated object reference for existing objects
-- (integer) container's AUID for objects that have entered containers (since they're not truly deleted)
-- (string) "destroyed" for objects that have been directly deleted
local newbimap = require "bimap/bimap"
local AUIDs, AUIDs_rev = newbimap()
local function getAUID(obj) -- this one has no side effect
local GMNote = obj.getGMNotes()
return GMNote and GMNote:match("\nAUID: (%d+)$")
-- stupid workaround because TTS object string properties aren't always strings, they can also be nil
end
-- naively appends AUID to GMNote, as a side effect adds the object to AUIDs. Rarely used.
local function addAUID(obj)
local newAUID = #AUIDs + 1
obj.setGMNotes((obj.getGMNotes() or "") .. "\nAUID: " .. newAUID)
AUIDs[newAUID] = obj
return newAUID
end
-- sets and returns a GUID, overwrites existing AUID if any. used with onObjectSpawn if the object is not spawning from a container.
local function forceAddAUID(obj)
local newAUID = #AUIDs + 1
local newAUID_string = "\nAUID: " .. newAUID
local newGMNote, num_matches = obj.getGMNotes():gsub("\nAUID: %d+$", newAUIDString)
if num_matches == 1 then
obj.setGMNotes(newGMNote)
elseif num_matches == 0 then
obj.setGMNotes(newGMNote .. newAUID_string)
else
error("duplicate AUIDs on object with guid " .. obj.guid ", dumping its GMNote:\n" .. obj.getGMNotes())
end
AUIDs[newAUID] = obj
return newAUID
end
-- gets and returns AUID, or adds and returns one if it didn't exist yet. in either case, indexes the object in the AUIDs map.
local function startTracking(obj)
local objAUID = getAUID(obj)
if objAUID then
if not AUIDs[objAUID] then -- simply start tracking the object
AUIDs[objAUID] = obj
return objAUID
else -- if auid is taken, assign a new one
local newAUID = forceAddAUID(obj)
log(string.format("duplicate AUID found, reassigning new obj! old auid/guid: %s/%s, new auid: %s",
objAUID, AUIDs[objAUID].guid, newAUID))
return newAUID
end
else
return addAUID(obj) -- if no auid yet, add one.
end
end
-- Event Functions:
local function AUID_onLoad() -- called during onLoad()
for i,obj in ipairs(getAllObjects()) do
local objAUID = getAUID(obj)
if objAUID then
if not AUIDs[objAUID] then
AUIDs[objAUID] = obj
else
log(string.format("duplicate object with AUID %s found! guids (old and new): %s and %s",
objAUID, obj.guid, AUIDs[objAUID].guid))
end
else
addAUID(obj)
end
end
end
-- when an pre-existing object leaves a container, add it to the AUID map (unless that AUID is already taken).
function AUID_onObjectLeaveContainer(container, obj)
local objAUID = getAUID(obj)
if objAUID then
if not AUIDs[objAUID] then
AUIDs[objAUID] = obj
else
local newAUID = forceAddAUID(obj)
log(string.format("duplicate AUID found, reassigning new obj! old auid/guid: %s/%s, new auid: %s",
objAUID, AUIDs[objAUID].guid, newAUID))
return
end
else
addAUID(obj)
end
end
-- if the spawning object was not from a container, had no AUID, or its AUID was taken, then give it a new AUID
local function AUID_onObjectSpawn(obj)
if not AUIDs_rev[obj] then -- check that the object isn't tracked, but we shouldn't need to
forceAddAUID(obj)
end
end
-- when an object goes into a container, set its AUID to point at the container's AUID.
local function AUID_onObjectEnterContainer(container, obj)
local objAUID = AUIDs_rev[obj] and next(AUIDs_rev[obj]) -- first check if table exists, then get first (should be only) element
local containerAUID = AUIDs_rev[container] and next(AUIDs_rev[container])
if not AUIDs_rev[obj] or not AUIDs_rev[container] then
log(string.format("untracked object entering container, container guid: %s obj guid: %s",
container.guid, obj.guid))
return
end
if objAUID and containerAUID then
AUIDs[objAUID] = containerAUID
end
end
local function markDestroyed(destroyed_auid)
local contents = AUIDs_rev[destroyed_auid] -- the set of things that list destroyed obj as their container
if contents then
for key in pairs(contents) do
markDestroyed(key) -- could cause issues with more than 65535 objects? followup on performance
end
end
AUIDs[destroyed_auid] = "destroyed"
end
local function AUID_onObjectDestroy(dying_object)
local objAUID = getAUID(dying_object)
if not objAUID then
log("destroyed object had no AUID! guid: " .. obj.guid)
return
end
local AUID_entry = AUIDs[objAUID]
if not AUID_entry then
log("destroyed object had an AUID but was not tracked! guid: " .. obj.guid)
return
end
if AUID_entry == AUIDs_rev[dying_object] then -- if it's a number, then obj is in a tracked container and already accounted for.
markDestroyed(objAUID)
else
log(string.format("AUID entry of destroyed object %s was not an obj reference to itself! instead it was: %s",
objAUID, logString(AUID_entry)))
end
end
local EventManager = require('ge_tts/EventManager')
EventManager.addHandler('onObjectLeaveContainer', AUID_onObjectLeaveContainer)
EventManager.addHandler('onObjectSpawn', AUID_onObjectSpawn)
EventManager.addHandler('onObjectDestroy', AUID_onObjectDestroy)
EventManager.addHandler('onLoad', AUID_onLoad)
return {AUIDs = AUIDs, AUIDs_rev = AUIDs_rev, getAUID = getAUID, startTracking = startTracking}