diff --git a/lua/entities/gmod_wire_dynmemory.lua b/lua/entities/gmod_wire_dynmemory.lua new file mode 100644 index 0000000000..3a5fe85463 --- /dev/null +++ b/lua/entities/gmod_wire_dynmemory.lua @@ -0,0 +1,230 @@ +AddCSLuaFile() +DEFINE_BASECLASS( "base_wire_entity" ) +ENT.PrintName = "Wire Dynamic Memory" +ENT.Author = "Sebastian J., the gabe" +ENT.WireDebugName = "Dynamic Memory" + +if CLIENT then return end -- No more client + +function ENT:Initialize() + self:PhysicsInit(SOLID_VPHYSICS) + self:SetMoveType(MOVETYPE_VPHYSICS) + self:SetSolid(SOLID_VPHYSICS) + + self.Inputs = Wire_CreateInputs(self, {"Clk"}) + + self.Outputs = Wire_CreateOutputs(self, {"Out", "Size"}) + + self.Size = 1 + self.Memory = {} + self.Memory[0] = 0 + + --this flag assists in replacing the old ram gate chips + --when adv. dupe 2 spawns something, it seems to run Setup() at least twice + --at the first setup we successfully hijack the memory chip and imitate its capacity + --at the second setup, the size is set back to 1 since were not being initialized through FromGate() + --to fix this, the legacy flag disables resizing of the ram chip until it is duped and spawned in again, + --since at this point we dont have to hijack the old ram chip + self.Legacy = false + + --the old dynamic memory chips had persistence like the dhdd + --if this feature is ever wanted, the required code is all here (and dynmemory.lua), but commented out + --self.Persistent = false + + self.AddrWrite = 0 + self.AddrRead = 0 + self.AddrWriteY = 0 + self.AddrReadY = 0 + self.Clk = false + self.Data = 0 + + self.WOM = false + self.Bifurcate = false + self.BifurcateMagic = 0 +end + +function ENT:Setup(size, wom, bifurcate, legacy) + if self.Legacy then return end + self.WOM = (wom == 1) + self.Bifurcate = (bifurcate == 1) + + local inputbuilt = {} + + if not self.WOM then + if self.Bifurcate then + inputbuilt = {"Clk", "AddrReadX", "AddrReadY", "AddrWriteX", "AddrWriteY", "Data", "Reset"} + else + inputbuilt = {"Clk", "AddrRead", "AddrWrite", "Data", "Reset"} + end + else + if self.Bifurcate then + inputbuilt = {"Clk", "AddrWriteX", "AddrWriteY", "Data", "Reset"} + else + inputbuilt = {"Clk", "AddrWrite", "Data", "Reset"} + end + end + + self.Inputs = Wire_AdjustInputs(self, inputbuilt) + + local size = math.Clamp(math.floor(size or self.Size), 1, 2097152) --2mb limit + + if self.Bifurcate then + self.BifurcateMagic = math.floor(math.sqrt(size)) + size = self.BifurcateMagic * self.BifurcateMagic + end + + local overheap = size - self.Size + + if (overheap < 0) then + for i= size, self.Size -1 do + self.Memory[i] = nil + end + elseif (overheap > 0) then + for i = self.Size, size - 1 do + self.Memory[i] = 0 + end + end + self.Size = size + + local sstr = self.Size + local sunit = " Bytes" + + if self.Bifurcate then + sstr = tostring(self.BifurcateMagic) .. "x" .. tostring(self.BifurcateMagic) .. sunit + else + if (sstr >= 1048576) then + sunit = "MB" + sstr = math.floor(sstr / 10485.76) / 100 --shows up to 2 decimals + elseif (sstr >= 1024) then + sunit = "KB" + sstr = math.floor(sstr / 102.4) / 10 --shows up to 1 decimal + end + sstr = tostring(sstr) .. sunit + end + + self:SetOverlayText(sstr .. (self.WOM == true and " Write-Only" or "") .. " RAM" .. (self.Size >= 1024 and " (" .. self.Size .. " bytes)" or "") .. (legacy and " (Legacy)" or "") ) + + WireLib.TriggerOutput(self, "Size", self.Size) + self:CalcOutput() + + self.Legacy = legacy +end + +--[[function ENT:SetPersistent(val) + self.Persistent = val or self.Persistent +end]] + +function ENT:TriggerInput(iname, Value) + if (iname == "Reset") then + if (Value > 0) then + for i=0, self.Size - 1 do + self.Memory[i] = 0 + end + end + elseif (iname == "AddrWrite") or (iname == "AddrWriteX") then + self.AddrWrite = math.floor(Value) + elseif (iname == "AddrRead") or (iname == "AddrReadX") then + self.AddrRead = math.floor(Value) + elseif (iname == "AddrWriteY") then + self.AddrWriteY = math.floor(Value) + elseif (iname == "AddrReadY") then + self.AddrReadY = math.floor(Value) + elseif (iname == "Data") then + self.Data = Value + elseif (iname == "Clk") then + self.Clk = Value > 0 + end + self:CalcOutput() +end + +function ENT:CalcOutput() + if self.Bifurcate then + if self.Clk and self.AddrWrite >= 0 and self.AddrWrite < self.BifurcateMagic and self.AddrWriteY >= 0 and self.AddrWriteY < self.BifurcateMagic then + self:WriteCell(self.AddrWrite + self.AddrWriteY * self.BifurcateMagic, self.Data) + end + if not self.WOM and self.AddrRead >= 0 and self.AddrRead < self.BifurcateMagic and self.AddrReadY >= 0 and self.AddrReadY < self.BifurcateMagic then + WireLib.TriggerOutput(self, "Out", self.Memory[self.AddrRead + self.AddrReadY * self.BifurcateMagic]) + end + else + if self.Clk and self.AddrWrite < self.Size and self.AddrWrite >= 0 then + self:WriteCell(self.AddrWrite, self.Data) + end + if not self.WOM and self.AddrRead < self.Size and self.AddrRead >= 0 then + WireLib.TriggerOutput(self, "Out", self.Memory[self.AddrRead]) + end + end +end + +function ENT:ReadCell(Address) + Address = math.floor(tonumber(Address)) + if self.WOM or Address < 0 or Address >= self.Size then + return 0 + end + return self.Memory[Address] +end + +function ENT:WriteCell(Address, Value) + Address = math.floor(tonumber(Address)) + if Address < 0 or Address >= self.Size then + return false + end + self.Memory[Address] = Value or 0 + return true +end + +local gateconv = {} +--{size, write only, bifurcate} +gateconv["ram8"] = {8, 0, 0} +gateconv["ram64"] = {64, 0, 0} +gateconv["ram1k"] = {1024, 0, 0} +gateconv["ram32k"] = {32768, 0, 0} +gateconv["ram128k"] = {131072, 0, 0} +gateconv["ram64x64"] = {4096, 0, 1} +gateconv["wom4"] = {4, 1, 0} + +function ENT:FromGate(action) + if gateconv[action] then + self:Setup(gateconv[action][1], gateconv[action][2], gateconv[action][3], true) + return + end + self:Setup(1, 0, 0, true) --this shouldnt be able to happen +end + +function ENT:BuildDupeInfo() + local info = self.BaseClass.BuildDupeInfo(self) or {} + + info.MemSize = self.Size + info.WOM = (self.WOM and 1 or 0) + info.Bifurcate = (self.Bifurcate and 1 or 0) + --[[info.Persistent = self.Persistent + if (self.Persistent) then + info.Memory = {} + --same 256k limit as DHDD + for i=0, math.min(self.Size - 1, 262143) do + if (self.Memory[i]) then + info.Memory[i] = self.Memory[i] + end + end + end]] + + return info +end + +function ENT:ApplyDupeInfo(ply, ent, info, GetEntByID) + self.BaseClass.ApplyDupeInfo(self, ply, ent, info, GetEntByID) + + self:Setup(info.MemSize or 1, info.WOM or 0, info.Bifurcate or 0, false) + + --[[self.Persistent = info.Persistent + if (info.Persistent) then + info.Memory = info.Memory or {} + --same 256k (512^2) limit as DHDD + for i=0, math.min(self.Size - 1, 262143) do + if (info.Memory[i]) then + self.Memory[i] = info.Memory[i] + end + end + end]] +end + +duplicator.RegisterEntityClass("gmod_wire_dynmemory", WireLib.MakeWireEnt, "Data", "Size", "WOM", "Bifurcate")--, "Persistent") diff --git a/lua/entities/gmod_wire_gate.lua b/lua/entities/gmod_wire_gate.lua index 61c11efe2e..ec680b821a 100644 --- a/lua/entities/gmod_wire_gate.lua +++ b/lua/entities/gmod_wire_gate.lua @@ -227,6 +227,19 @@ function WireLib.MakeWireGate(ply, pos, ang, model, action, noclip) local gate = GateActions[action] if not gate or gate.is_banned then return end + if gate.Upgrade then + local limitstr = gate.Upgrade:sub(6).."s" + if IsValid(ply) and (not ply:CheckLimit(limitstr)) then return false end + local upgrade = ents.Create(gate.Upgrade) + upgrade:SetModel(model) + upgrade:SetAngles(ang) + upgrade:SetPos(pos) + upgrade:Spawn() + upgrade:FromGate(action) + upgrade:SetPlayer(ply) + if IsValid(ply) then ply:AddCount(limitstr, upgrade) end + return upgrade + end return WireLib.MakeWireEnt(ply, { Class = "gmod_wire_gate", Pos = pos, Angle = ang, Model = model }, action, noclip) end diff --git a/lua/wire/gates/memory.lua b/lua/wire/gates/memory.lua index a6af5d9301..4344b97432 100644 --- a/lua/wire/gates/memory.lua +++ b/lua/wire/gates/memory.lua @@ -130,7 +130,8 @@ GateActions["wom4"] = { end, label = function() return "Write Only Memory - 4 store" - end + end, + Upgrade = "gmod_wire_dynmemory", } GateActions["ram8"] = { @@ -175,7 +176,8 @@ GateActions["ram8"] = { gate.LatchStore[Address] = value return true end - end + end, + Upgrade = "gmod_wire_dynmemory" } GateActions["ram64"] = { @@ -216,7 +218,8 @@ GateActions["ram64"] = { gate.LatchStore[Address] = value return true end - end + end, + Upgrade = "gmod_wire_dynmemory" } GateActions["ram1k"] = { @@ -257,7 +260,8 @@ GateActions["ram1k"] = { gate.LatchStore[Address] = value return true end - end + end, + Upgrade = "gmod_wire_dynmemory" } GateActions["ram32k"] = { @@ -298,7 +302,8 @@ GateActions["ram32k"] = { gate.LatchStore[Address] = value return true end - end + end, + Upgrade = "gmod_wire_dynmemory" } GateActions["ram128k"] = { @@ -339,7 +344,8 @@ GateActions["ram128k"] = { gate.LatchStore[Address] = value return true end - end + end, + Upgrade = "gmod_wire_dynmemory" } GateActions["ram64x64"] = { @@ -387,7 +393,8 @@ GateActions["ram64x64"] = { gate.LatchStore[Address] = value return true end - end + end, + Upgrade = "gmod_wire_dynmemory" } GateActions["udcounter"] = { @@ -400,7 +407,7 @@ GateActions["udcounter"] = { local lClk = (Clk > 0) local lReset = (Reset > 0) if ((gate.PrevInc ~= lInc or gate.PrevDec ~= lDec or gate.PrevClk ~= lClk) and lClk) then - if (lInc) and (not lDec) and (not lReset) then + if lInc and not lDec and not lReset then gate.countStore = (gate.countStore or 0) + 1 elseif (not lInc) and (lDec) and (not lReset) then gate.countStore = (gate.countStore or 0) - 1 diff --git a/lua/wire/stools/dynmemory.lua b/lua/wire/stools/dynmemory.lua new file mode 100644 index 0000000000..9c8802be8d --- /dev/null +++ b/lua/wire/stools/dynmemory.lua @@ -0,0 +1,74 @@ +WireToolSetup.setCategory( "Memory" ) +WireToolSetup.open( "dynmemory", "Dynamic Memory Chip", "gmod_wire_dynmemory", nil, "Dynamic Memory Chips" ) + +if CLIENT then + language.Add( "Tool.wire_dynmemory.name", "Dynamic Memory Chip Tool (Wire)" ) + language.Add( "Tool.wire_dynmemory.desc", "Spawns a Dynamic Memory Chip" ) + language.Add( "Tool.wire_dynmemory.wom", "Write-Only Mode" ) + language.Add( "Tool.wire_dynmemory.womdesc", "Disables reading from memory. Affects highspeed access." ) + language.Add( "Tool.wire_dynmemory.bifurcate", "Bifurcate" ) + language.Add( "Tool.wire_dynmemory.bifurcatedesc", "Bifurcates address lines into ReadAddr(X,Y) and WriteAddr(X,Y). Memory size will be adjusted for round addresses. A memory size of 4096 would mean the bifurcated chip is 64x64. Has no effect on highspeed access." ) + --language.Add( "Tool.wire_dynmemory.pers", "Persistent Memory" ) + --language.Add( "Tool.wire_dynmemory.persdesc", "Should contents save when duped?" ) + TOOL.Information = { { name = "left", text = "Create/Update " .. TOOL.Name }, { name = "right", text = "Copy " .. TOOL.Name } } + + --language.Add( "Tool.wire_dynmemory.note", "NOTE: Persistence only saves the first\n512^2 values (256kb) to prevent\nmassive dupe files and lag." ) + + TOOL.ClientConVar["model"] = "models/jaanus/wiretool/wiretool_gate.mdl" + TOOL.ClientConVar["size"] = 16384 + TOOL.ClientConVar["wom"] = 0 + TOOL.ClientConVar["bifurcate"] = 0 + --TOOL.ClientConVar["persistent"] = 0 + + function TOOL.BuildCPanel( panel ) + ModelPlug_AddToCPanel(panel, "gate", "wire_dynmemory", nil, 4) + + panel:NumSlider("Memory Size","wire_dynmemory_size",1,2097152,0) + + panel:AddControl("Checkbox", { + Label = "#Tool.wire_dynmemory.wom", + Description = "", + Command = "wire_dynmemory_wom" + }) + + panel:Help("#Tool.wire_dynmemory.womdesc") + + panel:AddControl("Checkbox", { + Label = "#Tool.wire_dynmemory.bifurcate", + Description = "", + Command = "wire_dynmemory_bifurcate" + }) + + panel:Help("#Tool.wire_dynmemory.bifurcatedesc") + + --[[panel:AddControl("Checkbox", { + Label = "#Tool.wire_dynmemory.pers", + Description = "#Tool.wire_dynmemory.persdesc", + Command = "wire_dynmemory_persistent" + }) + panel:Help("#Tool.wire_dynmemory.note")]] + end + + WireToolSetup.setToolMenuIcon( "icon16/database.png" ) +else + function TOOL:GetConVars() + return self:GetClientNumber( "size" ), self:GetClientNumber( "wom" ), self:GetClientNumber( "bifurcate" )--, self:GetClientNumber( "persistent" ) + end +end +WireToolSetup.BaseLang() +WireToolSetup.SetupMax( 32 ) + +function TOOL:RightClick(trace) + if (CLIENT) then return true end + + if (trace.Entity and trace.Entity:IsValid()) then + if (trace.Entity:GetClass() == "gmod_wire_dynmemory") then + self:GetOwner():ConCommand("wire_dynmemory_size "..trace.Entity.Size.."\n") + self:GetOwner():ConCommand("wire_dynmemory_wom "..(trace.Entity.WOM and "1" or "0").."\n") + self:GetOwner():ConCommand("wire_dynmemory_bifurcate "..(trace.Entity.Bifurcate and "1" or "0").."\n") + return true + end + end + + return false +end